"
"%s | " // name
"%s | " // sbatt (Battery Indicator)
"" // slqi
), shortaddr,
device.modelId ? device.modelId : "",
device.manufacturerId ? device.manufacturerId : "",
name, 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), PSTR(" | 🕗%02d%c"),
color, color, color, val, unit);
}
}
WSContentSend_PD(PSTR(
" | " // Close LQI
"%s{e}" // dhm (Last Seen)
), 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(PSTR("┆"));
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(PSTR("┆"));
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(PSTR(" ⚪ %dK"), 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
LightStateClass::HsToRgb(light.getHue(), sat, &r, &g, &b);
WSContentSend_P(PSTR(" #%02X%02X%02X"), r,g,b,r,g,b);
} else if (light.validX() && light.validY() && (channels >= 3)) {
uint8_t r,g,b;
LightStateClass::XyToRgb(light.getX() / 65535.0f, light.getY() / 65535.0f, &r, &g, &b);
WSContentSend_P(PSTR(" #%02X%02X%02X"), 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(PSTR("{t}")); // Terminate current multi column table and open new table
if (zigbee.permit_end_time) {
// PermitJoin in progress
WSContentSend_P(PSTR(" [ Devices allowed to join ] ")); // Terminate current multi column table and open new table
}
#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("Location","/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();
}
WSContentStart_P(PSTR("Tasmota Zigbee Mapping"));
WSContentSendStyle();
if (zigbee.init_phase) {
WSContentSend_P(PSTR("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("Mapping in progress (%d s. remaining)"), mapping_remaining);
WSContentSend_P(HTTP_AUTO_REFRESH_PAGE);
} else if (!zigbee.mapping_ready) {
WSContentSend_P(PSTR("No mapping"));
} else {
WSContentSend_P(PSTR(
""
"Unable to load vis.js "
""
));
WSContentSend_P(HTTP_BTN_ZB_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
#ifdef USE_ZIGBEE_EZSP
ZigbeeGlowPermitJoinLight();
#endif // USE_ZIGBEE_EZSP
}
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);
break;
case FUNC_SAVE_BEFORE_RESTART:
#ifdef USE_ZIGBEE_EZSP
hibernateAllData();
#endif // USE_ZIGBEE_EZSP
restoreDumpAllDevices();
break;
}
}
return result;
}
#endif // USE_ZIGBEE
| | |