"
"%s | " // name
"%s | " // sbatt (Battery Indicator)
"" // slqi
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_BATTERY
" "
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_LAST_SEEN
" 🕗%02d%c"
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_COLOR_RGB
" #%02X%02X%02X"
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_LINE_START
" | ┆"
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_LIGHT_CT
" ⚪ %dK"
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_END_STATUS
" | " // Close LQI
"%s{e}" // dhm (Last Seen)
"\0"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=ZB_WEB_LINE_END
"{t}"
"\0"
; // end of list
// Use the tool at https://tasmota.hadinger.fr/util and choose "Compress Strings template with Unishox"
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++ DO NOT EDIT BELOW ++++++++++++++++++++
// ++++++++++++++++++++vvvvvvvvvvvvvvvvvvv++++++++++++++++++++
enum {
ZB_WEB_CSS=0,
ZB_WEB_PERMITJOIN_ACTIVE=507,
ZB_WEB_VIS_JS_BEFORE=561,
ZB_WEB_VIS_JS_AFTER=1034,
ZB_WEB_AUTO_REFRESH=1098,
ZB_WEB_MAP_REFRESH=1164,
ZB_WEB_STATUS_LINE=1230,
ZB_WEB_BATTERY=1338,
ZB_WEB_LAST_SEEN=1388,
ZB_WEB_COLOR_RGB=1436,
ZB_WEB_LINE_START=1496,
ZB_WEB_LIGHT_CT=1536,
ZB_WEB_END_STATUS=1591,
ZB_WEB_LINE_END=1608,
};
// Compressed from 1627 to 1118, -31.3%
const char ZB_WEB[] PROGMEM = "\x00\x66\x3D\x0E\xCA\xB1\xC1\x33\xF0\xF6\xD1\xEE\x3D\x3D\x46\x41\x33\xF0\xE8\x6D"
"\xA1\x15\x08\x79\xF6\x51\xDD\x3C\xCC\x6F\xFD\x47\x58\x62\xB4\x21\x0E\xF1\xED\x1F"
"\xD1\x28\x51\xE6\x72\x99\x0C\x36\x1E\x0C\x67\x51\xD7\xED\x36\xB3\xCC\xE7\x99\xF4"
"\x7D\x1E\xE2\x04\x3C\x40\x2B\x04\x3C\x28\x10\xB0\x93\x99\xA4\x30\xD8\x08\x36\x8E"
"\x83\xA8\xF6\x8D\xBF\x8F\x6F\x1D\x7F\xD1\xE1\x54\x79\x9C\x8C\x86\x1B\x0F\x07\xB8"
"\xE8\x2A\x2B\xBE\x7B\x42\xDE\x67\x58\xA7\xA3\xC2\xA8\xF3\x39\x4C\x86\x1B\x0F\x71"
"\xD0\x71\xB0\xF6\x82\x14\xC3\x93\x08\x61\xB0\xF0\x08\x39\x49\xC9\x84\x30\xD8\x78"
"\x13\x7C\x30\x2B\x32\x3C\xF7\x82\xDE\x67\x58\xE0\xB0\x33\x43\xC0\xEC\xF8\x8F\xE7"
"\x99\xC8\x43\x0D\x8B\xD8\x16\x88\x83\x17\xFF\xBE\xA2\x0F\x02\xCF\x9E\x07\x58\x66"
"\x83\xDF\xC1\x7C\x21\xD6\x1E\x05\x9F\x3C\xCC\xEF\xE7\x74\xEB\x3A\xC3\x08\xEA\x3C"
"\x8C\x18\x30\x77\x8F\x71\xD3\xDA\x7B\x41\x2B\x33\x30\x13\x36\x1E\x2C\x2D\x1E\xE3"
"\xAF\x69\x8D\xF1\xE6\x60\x26\x6C\x3A\xDF\x08\x78\x04\x3D\xCC\xE6\x90\xC3\x61\xE0"
"\x65\x88\x26\xF0\xF1\xE6\x71\x9E\xE3\xA1\x7B\x56\x82\x17\x0A\x07\x2C\x86\x1B\x0F"
"\x2A\x01\x93\xC2\x30\xC3\x60\x21\x6F\xC7\x5F\xEC\x4D\x17\xE3\xCC\xE5\x90\xC3\x60"
"\x26\xEE\x47\x91\xF4\x71\xF1\x1B\x0F\x71\xD3\xDA\x8E\x83\x8E\x32\x04\x3E\x16\xCE"
"\x56\x9F\x47\xD1\x02\x15\x03\x90\x81\x0E\x81\xCD\x64\x08\x94\x0E\x51\x02\x1D\x03"
"\x9E\x20\x45\xC1\x0E\x59\x02\x27\x12\xE7\x1B\x3E\x8F\xA3\xDC\x74\x2C\x39\x6C\xF6"
"\x96\x0C\xB0\xF6\x8C\x8F\x33\xA1\xCB\x3D\xC7\xA1\xD8\x40\x83\xCA\x24\xE1\x7C\xF4"
"\x18\x7E\x1E\x83\x8F\xC3\xDE\x47\xA7\x86\x5F\x2F\x51\x90\x4C\xF8\x7D\x82\x16\xCE"
"\x71\xFD\x9E\x0F\xB3\xF0\xFA\x2F\x1E\x87\x67\x86\x5F\x1F\x88\xF7\xCF\x43\xB0\x71"
"\xF8\x7A\x1D\x83\x0F\xC9\xC2\xF9\xE9\xE0\xFF\xA3\x29\x51\x90\xC6\x7C\x3D\x94\xCD"
"\x94\x76\x1A\xEC\xCE\xC1\x06\x91\xEC\x5E\xF8\x67\xC3\xD8\x2A\x2B\xA8\x67\x8F\x33"
"\xB0\xEC\x17\xC3\x0D\x07\x8E\x81\xE0\xD3\xB0\xCF\x7C\x75\xF3\xA1\xFC\xF9\xA1\xD9"
"\xEA\xBE\x12\xC2\xCE\x67\x60\xB1\xA2\x02\x3D\x73\xA0\xDD\xE3\xA1\xAF\xC7\xB0\xFC"
"\x3D\x0E\xC0\x41\xCB\x0F\xC3\xD0\x4D\x33\x5A\x21\xF0\xF6\x0D\x32\x04\x2C\x2A\x01"
"\xF6\x02\x17\x2A\x01\xC7\xB0\x13\x78\x9C\x30\x60\xC1\xE0\x10\xF8\x1C\x38\xD9\x02"
"\x17\x32\x27\x3E\xD9\x0C\x36\x02\x1F\x22\x47\x31\xB2\x04\x4E\x3A\x01\x1B\x98\xA0"
"\xB4\x78\x55\x0F\x7E\xCC\x8F\x1F\x7E\xD3\x6B\x3C\xC7\x65\x0A\x3C\x1E\xC3\xF0\x85"
"\xF5\x8E\x09\xAA\xC4\x16\x58\x88\xCF\x7C\x74\x35\xF8\xF4\x3B\x04\xD3\x33\xF0\x16"
"\x78\x63\x3F\x0C\xEF\xE8\x3C\xEA\xBD\xE7\xF3\xE0\x98\x18\xB1\xAF\xA8\xE8\x3C\xE8"
"\x98\x4C\x6B\xEA\x21\xC6\x45\xA2\x1D\xD0\x46\xE0\xC8\xEF\x1E\x0C\xEF\xEB\x06\x56"
"\xE7\x78\xF8\x7B\x47\xBF\x82\xC6\x78\xF3\x3D\xB8\x79\x9E\xDF\x0A\xB1\x8C\xF3\x3D"
"\x81\xEF\xC3\x09\x9E\xC3\xA8\x10\x78\x3D\x3D\x87\x90\x87\x37\x4F\x61\xEE\x3A\x8B"
"\xE0\x89\x70\x76\x1B\x01\x16\xC9\x81\xC7\x3C\x7B\x0F\x71\xD4\x4C\x11\x2C\xB0\x82"
"\xD1\x9E\x04\x6C\x6A\xC4\x30\x7B\x0F\x71\xEE\x3D\xC7\x83\x3B\xFA\x12\xEA\xCF\x87"
"\xB6\x70\xBE\x08\x32\x41\x0B\x6C\x3E\x73\x1F\x46\x7B\xE3\xA1\x70\x20\xCC\x3B\xA0"
"\x89\xC1\x49\xD4\x25\xD5\x9D\x40\x85\xC0\x29\xDE\x3C\x02\x27\x20\xC0\x87\xCB\xA9"
"\xF9\xE7\x45\x5A\x35\xE0\xBA\x3B\xA6\x05\xF0\x75\xB9\xC7\x74\xEF\x1E\xD0\xB0\x3B"
"\xAD\xCE\x3A\x7D\x85\x96\x21\xDD\x3B\xC7\x83\xDC\x75\x1C\x89\x32\x04\x8C\x78\x61"
"\xF8\x7A\x1D\x83\x0F\xC3\xD0\xC6\x7C\x6A\xB0\xEB\x73\x8F\x87\xD9\xB4\x77\xCF\xB4"
"\x35\xD0\xAC\x10\xF8\x7D\x8F\x3A\x3E\xCF\xC3\xD0\x70\xBA\xAC\xE3\xF0\xFA\xF1\xE8"
"\x76\x02\x14\x73\xD0\xEC\x31\x9F\x1A\x7E\x4E\x17\xCF\x4A\xFA\x0C\x2B\xF7\x8F\x87"
"\xD9\xB6\x84\x42\xAB\xE7\xD9\xF8\x7A\x50\x87\xE1\xE8\x39\x56\xD0\x4C\xF8\x7D\x9C"
"\x64\x6C\x3E\x8E\x3C\x22\x36\x23\xEB\xC8\xEB\x47\xD7\x81\x07\xA0\x7E\x38\xFC\x3D"
"\x0E\xCA\x10\xFC\x3D\x28\x43\xF0\xFA\xF0\x22\x47\x3D\x04\xD3\x30\x43\xC4\x88\x22"
"\x35\x16\xA3\xEB\xC7\xD8\x21\xE7\x1E\xD3\xEC\xFC\x9C\x2F\x9E\x9A\x08\x52\xCF\x60"
"\xEA\x3D\x80\x85\x82\x9E\xC3\xE8\x43\xE8\xFA\x04\x4E\x7F\x8E\xB3\xAC\x70\x47\x99"
"\xF4\x20\xC3\x61\xEC\x3F\x0F\x43\xB3\x4F\xC9\xC2\xF9\xE9\x42\x02\x1D\x70\x44\xE8"
"\xA7\x1C\xA2\x36\x1F\x47\x1D\x11\xB0\xFA\x38\xE8\x8D\x87\xB0\xFC\x3F\x47\x91\xB0"
"\xE4\x22\x30\x73\x77\xC7\x83\xE9\xD1\x08\x7D\x07\x38\x5F\x40\x8D\x9F\x9B\x01\x1B"
"\x32\x0C\x23\xCC\xF2\x3E\x8E\x3A\x22\x36\x1F\x47\x1D\x11\x1B\x0F\xA3\x8E\x88\x8D"
"\x80\x83\x9D\x82\x44\xF0\x47\xE1\x98\x10\xF8\x62\x41\xE0\x5E\x19\x7C\x7C\x3D\x87"
"\x30\xF6\x1F\x87\xE8\xF2\x59\xEF\x9E\x0A\x70\xBE\x08\x5D\x15\xA0\x42\xE0\x6C\x83"
"\x2A\x2B\x47\xD0\x87\xB0\xFC\x3D\x3C\x36\xC2\x08\xFC\x3F\x47\x91\xC5\xF5\xF3\xC1"
"\xDC\x3D\x0E\xC2\x04\x19\x87\xD0\x84\x68\x08\x5D\x16\xC9\xC2\xF8\x21\x74\x18\x4E"
"\xCA\x10\xFC\x3E\xBC\x7B\x59\xEE\x9C\x2F\x82\x3F\x4E\x90\x10\x79\x23\x9C\x2F\x9B";
// ++++++++++++++++++++^^^^^^^^^^^^^^^^^^^++++++++++++++++++++
// ++++++++++++++++++++ DO NOT EDIT ABOVE ++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// comparator function used to sort Zigbee devices by alphabetical order (if friendlyname)
// then by shortaddr if they don't have friendlyname
int device_cmp(uint8_t a, uint8_t b) {
const Z_Device &dev_a = zigbee_devices.devicesAt(a);
const Z_Device &dev_b = zigbee_devices.devicesAt(b);
const char * fn_a = dev_a.friendlyName;
const char * fn_b = dev_b.friendlyName;
if (fn_a && fn_b) {
return strcasecmp(fn_a, fn_b);
} else if (!fn_a && !fn_b) {
return (int32_t)dev_a.shortaddr - (int32_t)dev_b.shortaddr;
} else {
if (fn_a) return -1;
else return 1;
}
}
// Convert seconds to a string representing days, hours or minutes present in the n-value.
// The string will contain the most coarse time only, rounded down (61m == 01h, 01h37m == 01h).
// Inputs:
// - seconds: uint32_t representing some number of seconds
// Outputs:
// - char for unit (d for day, h for hour, m for minute)
// - the hex color to be used to display the text
//
uint32_t convert_seconds_to_dhm(uint32_t seconds, char *unit, uint8_t *color){
static uint32_t conversions[3] = {24 * 3600, 3600, 60};
static char units[3] = { 'd', 'h', 'm'}; // day, hour, minute
uint8_t color_text_8 = WebColor(COL_TEXT) & 0xFF; // color of text on 8 bits
uint8_t color_back_8 = WebColor(COL_BACKGROUND) & 0xFF; // color of background on 8 bits
uint8_t colors[3] = { (uint8_t) changeUIntScale(6, 0, 16, color_back_8, color_text_8), // 6/16 of text
(uint8_t) changeUIntScale(10, 0, 16, color_back_8, color_text_8), // 10/16 of text color
color_text_8};
for(int i = 0; i < 3; ++i) {
*color = colors[i];
*unit = units[i];
if (seconds > conversions[i]) { // always pass even if 00m
return seconds / conversions[i];
}
}
return 0;
}
const char HTTP_BTN_ZB_BUTTONS[] PROGMEM =
""
""
"";
void ZigbeeShow(bool json)
{
if (json) {
return;
#ifdef USE_WEBSERVER
} else {
UnishoxStrings msg(ZB_WEB);
uint32_t zigbee_num = zigbee_devices.devicesSize();
if (zigbee_num > 0) {
if (zigbee_num > 255) { zigbee_num = 255; }
WSContentSend_P(msg[ZB_WEB_CSS], WebColor(COL_TEXT));
// WSContentSend_compressed(ZB_WEB, 0);
// sort elements by name, then by id
uint8_t sorted_idx[zigbee_num];
for (uint32_t i = 0; i < zigbee_num; i++) {
sorted_idx[i] = i;
}
// insertion sort
for (uint32_t i = 1; i < zigbee_num; i++) {
uint8_t key = sorted_idx[i];
uint8_t j = i;
while ((j > 0) && (device_cmp(sorted_idx[j - 1], key) > 0)) {
sorted_idx[j] = sorted_idx[j - 1];
j--;
}
sorted_idx[j] = key;
}
uint32_t now = Rtc.utc_time;
for (uint32_t i = 0; i < zigbee_num; i++) {
const Z_Device &device = zigbee_devices.devicesAt(sorted_idx[i]);
uint16_t shortaddr = device.shortaddr;
char *name = (char*) device.friendlyName;
char sdevice[33];
if (nullptr == name) {
snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr);
name = sdevice;
}
char sbatt[64];
snprintf_P(sbatt, sizeof(sbatt), PSTR(" "));
if (device.validBatteryPercent()) {
snprintf_P(sbatt, sizeof(sbatt),
msg[ZB_WEB_BATTERY],
device.batterypercent, changeUIntScale(device.batterypercent, 0, 100, 0, 14)
);
}
uint32_t num_bars = 0;
char slqi[4];
slqi[0] = '-';
slqi[1] = '\0';
if (device.validLqi()){
num_bars = changeUIntScale(device.lqi, 0, 254, 0, 4);
snprintf_P(slqi, sizeof(slqi), PSTR("%d"), device.lqi);
}
WSContentSend_PD(msg[ZB_WEB_STATUS_LINE],
shortaddr,
device.modelId ? EscapeHTMLString(device.modelId).c_str() : "",
device.manufacturerId ? EscapeHTMLString(device.manufacturerId).c_str() : "",
EscapeHTMLString(name).c_str(), sbatt, slqi);
if(device.validLqi()) {
for(uint32_t j = 0; j < 4; ++j) {
WSContentSend_PD(PSTR(""), j, (num_bars < j) ? PSTR(" o30") : PSTR(""));
}
}
char dhm[48];
snprintf_P(dhm, sizeof(dhm), PSTR(" "));
if (device.validLastSeen()) {
char unit;
uint8_t color;
uint16_t val = convert_seconds_to_dhm(now - device.last_seen, &unit, &color);
if (val < 100) {
snprintf_P(dhm, sizeof(dhm), msg[ZB_WEB_LAST_SEEN],
color, color, color, val, unit);
}
}
WSContentSend_PD(msg[ZB_WEB_END_STATUS], dhm );
// Sensors
const Z_Data_Thermo & thermo = device.data.find();
if (&thermo != nullptr) {
bool validTemp = thermo.validTemperature();
bool validTempTarget = thermo.validTempTarget();
bool validThSetpoint = thermo.validThSetpoint();
bool validHumidity = thermo.validHumidity();
bool validPressure = thermo.validPressure();
if (validTemp || validTempTarget || validThSetpoint || validHumidity || validPressure) {
WSContentSend_P(msg[ZB_WEB_LINE_START]);
if (validTemp) {
char buf[12];
dtostrf(thermo.getTemperature() / 100.0f, 3, 1, buf);
WSContentSend_PD(PSTR(" ☀️ %s°C"), buf);
}
if (validTempTarget) {
char buf[12];
dtostrf(thermo.getTempTarget() / 100.0f, 3, 1, buf);
WSContentSend_PD(PSTR(" 🎯 %s°C"), buf);
}
if (validThSetpoint) {
WSContentSend_PD(PSTR(" ⚙️ %d%%"), thermo.getThSetpoint());
}
if (validHumidity) {
WSContentSend_P(PSTR(" 💧 %d%%"), (uint16_t)(thermo.getHumidity() / 100.0f + 0.5f));
}
if (validPressure) {
WSContentSend_P(PSTR(" ⛅ %d hPa"), thermo.getPressure());
}
WSContentSend_P(PSTR("{e}"));
}
}
// Light, switches and plugs
const Z_Data_OnOff & onoff = device.data.find();
bool onoff_display = (&onoff != nullptr) ? onoff.validPower() : false;
const Z_Data_Light & light = device.data.find();
bool light_display = (&light != nullptr) ? light.validDimmer() : false;
const Z_Data_Plug & plug = device.data.find();
bool plug_voltage = (&plug != nullptr) ? plug.validMainsVoltage() : false;
bool plug_power = (&plug != nullptr) ? plug.validMainsPower() : false;
if (onoff_display || light_display || plug_voltage || plug_power) {
int8_t channels = device.getLightChannels();
if (channels < 0) { channels = 5; } // if number of channel is unknown, display all known attributes
WSContentSend_P(msg[ZB_WEB_LINE_START]);
if (onoff_display) {
WSContentSend_P(PSTR(" %s"), onoff.getPower() ? PSTR(D_ON) : PSTR(D_OFF));
}
if (&light != nullptr) {
if (light.validDimmer() && (channels >= 1)) {
WSContentSend_P(PSTR(" 🔅 %d%%"), changeUIntScale(light.getDimmer(),0,254,0,100));
}
if (light.validCT() && ((channels == 2) || (channels == 5))) {
uint32_t ct_k = (((1000000 / light.getCT()) + 25) / 50) * 50;
WSContentSend_P(msg[ZB_WEB_LIGHT_CT], light.getCT(), ct_k);
}
if (light.validHue() && light.validSat() && (channels >= 3)) {
uint8_t r,g,b;
uint8_t sat = changeUIntScale(light.getSat(), 0, 254, 0, 255); // scale to 0..255
HsToRgb(light.getHue(), sat, &r, &g, &b);
WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b);
} else if (light.validX() && light.validY() && (channels >= 3)) {
uint8_t r,g,b;
XyToRgb(light.getX() / 65535.0f, light.getY() / 65535.0f, &r, &g, &b);
WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b);
}
}
if (plug_voltage || plug_power) {
WSContentSend_P(PSTR(" ⚡ "));
if (plug_voltage) {
WSContentSend_P(PSTR(" %dV"), plug.getMainsVoltage());
}
if (plug_power) {
WSContentSend_P(PSTR(" %dW"), plug.getMainsPower());
}
}
WSContentSend_P(PSTR("{e}"));
}
}
WSContentSend_P(msg[ZB_WEB_LINE_END]); // Terminate current multi column table and open new table
}
if (zigbee.permit_end_time) {
// PermitJoin in progress
WSContentSend_P(msg[ZB_WEB_PERMITJOIN_ACTIVE], PSTR(D_ZIGBEE_PERMITJOIN_ACTIVE));
}
#endif
}
}
// Web handler to refresh the map, the redirect to show map
void ZigbeeMapRefresh(void) {
if ((!zigbee.init_phase) && (!zigbee.mapping_in_progress)) {
ZigbeeMapAllDevices();
}
Webserver->sendHeader(F("Location"),F("/zbm")); // Add a header to respond with a new location for the browser to go to the home page again
Webserver->send(302);
}
// Display a graphical representation of the Zigbee map using vis.js network
void ZigbeeShowMap(void) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Zigbee Mapper"));
// if no map, then launch a new mapping
if ((!zigbee.init_phase) && (!zigbee.mapping_ready) && (!zigbee.mapping_in_progress)) {
ZigbeeMapAllDevices();
}
UnishoxStrings msg(ZB_WEB);
WSContentStart_P(PSTR(D_ZIGBEE_MAPPING_TITLE));
WSContentSendStyle();
if (zigbee.init_phase) {
WSContentSend_P(PSTR(D_ZIGBEE_NOT_STARTED));
} else if (zigbee.mapping_in_progress) {
int32_t mapping_remaining = 1 + (zigbee.mapping_end_time - millis()) / 1000;
if (mapping_remaining < 0) { mapping_remaining = 0; }
WSContentSend_P(PSTR(D_ZIGBEE_MAPPING_IN_PROGRESS_SEC), mapping_remaining);
WSContentSend_P(msg[ZB_WEB_AUTO_REFRESH]);
} else if (!zigbee.mapping_ready) {
WSContentSend_P(PSTR(D_ZIGBEE_MAPPING_NOT_PRESENT));
} else {
WSContentSend_P(msg[ZB_WEB_VIS_JS_BEFORE]);
zigbee_mapper.dumpInternals();
WSContentSend_P(msg[ZB_WEB_VIS_JS_AFTER]);
WSContentSend_P(msg[ZB_WEB_MAP_REFRESH], PSTR(D_ZIGBEE_MAP_REFRESH));
}
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv23(uint8_t function)
{
bool result = false;
if (zigbee.active) {
switch (function) {
case FUNC_EVERY_50_MSECOND:
if (!zigbee.init_phase) {
zigbee_devices.runTimer();
}
break;
case FUNC_LOOP:
#ifdef USE_ZIGBEE_EZSP
if (ZigbeeUploadXmodem()) {
return false;
}
#endif
if (ZigbeeSerial) {
ZigbeeInputLoop();
ZigbeeOutputLoop(); // send any outstanding data
ZigbeePermitJoinUpdate(); // timer for permit join
}
if (zigbee.state_machine) {
ZigbeeStateMachine_Run();
}
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
ZigbeeShow(false);
break;
// GUI xmodem
case FUNC_WEB_ADD_HANDLER:
#ifdef USE_ZIGBEE_EZSP
WebServer_on(PSTR("/" WEB_HANDLE_ZIGBEE_XFER), HandleZigbeeXfer);
#endif // USE_ZIGBEE_EZSP
WebServer_on(PSTR("/zbm"), ZigbeeShowMap, HTTP_GET); // add web handler for Zigbee map
WebServer_on(PSTR("/zbr"), ZigbeeMapRefresh, HTTP_GET); // add web handler for Zigbee map refresh
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
WSContentSend_P(HTTP_BTN_ZB_BUTTONS);
break;
#endif // USE_WEBSERVER
case FUNC_PRE_INIT:
ZigbeeInit();
break;
case FUNC_COMMAND:
result = DecodeCommand(kZbCommands, ZigbeeCommand, kZbSynonyms);
break;
case FUNC_SAVE_BEFORE_RESTART:
if (!zigbee.init_phase) {
hibernateAllData();
restoreDumpAllDevices();
}
break;
}
}
return result;
}
#endif // USE_ZIGBEE
| |