Merge pull request #10025 from s-hadinger/zigbee_optim

Zigbee code size optimization
This commit is contained in:
s-hadinger 2020-11-30 19:51:15 +01:00 committed by GitHub
commit a178ef459b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 62 deletions

View File

@ -257,6 +257,8 @@ public:
inline Z_attribute & addAttribute(const __FlashStringHelper * name, uint8_t suffix = 0) {
return addAttribute((const char*) name, true, suffix);
}
// smaller version called often to reduce code size
Z_attribute & addAttributePMEM(const char * name);
// Remove from list by reference, if null or not found, then do nothing
inline void removeAttribute(const Z_attribute * attr) { remove(attr); }
@ -297,6 +299,11 @@ public:
bool mergeList(const Z_attribute_list &list2);
};
Z_attribute & Z_attribute_list::addAttributePMEM(const char * name) {
return addAttribute(name, true, 0);
}
/*********************************************************************************************\
*
* Implementation for Z_attribute

View File

@ -637,28 +637,30 @@ void Z_Device::jsonAddDeviceNamme(Z_attribute_list & attr_list) const {
bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname?
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
attr_list.addAttribute(F(D_JSON_ZIGBEE_DEVICE)).setStr(hex);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setStr(hex);
if (fname) {
attr_list.addAttribute(F(D_JSON_ZIGBEE_NAME)).setStr(fname);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAME)).setStr(fname);
}
}
// Add "IEEEAddr":"0x1234567812345678"
void Z_Device::jsonAddIEEE(Z_attribute_list & attr_list) const {
char hex[22];
hex[0] = '0'; // prefix with '0x'
hex[1] = 'x';
Uint64toHex(longaddr, &hex[2], 64);
attr_list.addAttribute(F("IEEEAddr")).setStr(hex);
attr_list.addAttributePMEM(PSTR("IEEEAddr")).setStr(hex);
}
// Add "ModelId":"","Manufacturer":""
void Z_Device::jsonAddModelManuf(Z_attribute_list & attr_list) const {
if (modelId) {
attr_list.addAttribute(F(D_JSON_MODEL D_JSON_ID)).setStr(modelId);
attr_list.addAttributePMEM(PSTR(D_JSON_MODEL D_JSON_ID)).setStr(modelId);
}
if (manufacturerId) {
attr_list.addAttribute(F("Manufacturer")).setStr(manufacturerId);
attr_list.addAttributePMEM(PSTR("Manufacturer")).setStr(manufacturerId);
}
}
// Add "Endpoints":[...]
void Z_Device::jsonAddEndpoints(Z_attribute_list & attr_list) const {
JsonGeneratorArray arr_ep;
@ -667,7 +669,7 @@ void Z_Device::jsonAddEndpoints(Z_attribute_list & attr_list) const {
if (0x00 == endpoint) { break; }
arr_ep.add(endpoint);
}
attr_list.addAttribute(F("Endpoints")).setStrRaw(arr_ep.toString().c_str());
attr_list.addAttributePMEM(PSTR("Endpoints")).setStrRaw(arr_ep.toString().c_str());
}
// Add "Config":["",""...]
void Z_Device::jsonAddConfig(Z_attribute_list & attr_list) const {
@ -682,7 +684,7 @@ void Z_Device::jsonAddConfig(Z_attribute_list & attr_list) const {
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
arr_data.addStr(key);
}
attr_list.addAttribute(F("Config")).setStrRaw(arr_data.toString().c_str());
attr_list.addAttributePMEM(PSTR("Config")).setStrRaw(arr_data.toString().c_str());
}
// Add All data attributes
void Z_Device::jsonAddDataAttributes(Z_attribute_list & attr_list) const {
@ -693,15 +695,15 @@ void Z_Device::jsonAddDataAttributes(Z_attribute_list & attr_list) const {
}
// Add "BatteryPercentage", "LastSeen", "LastSeenEpoch", "LinkQuality"
void Z_Device::jsonAddDeviceAttributes(Z_attribute_list & attr_list) const {
attr_list.addAttribute(F("Reachable")).setBool(getReachable());
if (validBatteryPercent()) { attr_list.addAttribute(PSTR("BatteryPercentage")).setUInt(batterypercent); }
attr_list.addAttributePMEM(PSTR("Reachable")).setBool(getReachable());
if (validBatteryPercent()) { attr_list.addAttributePMEM(PSTR("BatteryPercentage")).setUInt(batterypercent); }
if (validLastSeen()) {
if (Rtc.utc_time >= last_seen) {
attr_list.addAttribute(PSTR("LastSeen")).setUInt(Rtc.utc_time - last_seen);
attr_list.addAttributePMEM(PSTR("LastSeen")).setUInt(Rtc.utc_time - last_seen);
}
attr_list.addAttribute(PSTR("LastSeenEpoch")).setUInt(last_seen);
attr_list.addAttributePMEM(PSTR("LastSeenEpoch")).setUInt(last_seen);
}
if (validLqi()) { attr_list.addAttribute(PSTR(D_CMND_ZIGBEE_LINKQUALITY)).setUInt(lqi); }
if (validLqi()) { attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_LINKQUALITY)).setUInt(lqi); }
}
@ -709,8 +711,8 @@ void Z_Device::jsonAddDeviceAttributes(Z_attribute_list & attr_list) const {
void Z_Device::jsonLightState(Z_attribute_list & attr_list) const {
if (valid()) {
// dump all known values
attr_list.addAttribute(F("Reachable")).setBool(getReachable());
if (validPower()) { attr_list.addAttribute(F("Power")).setUInt(getPower()); }
attr_list.addAttributePMEM(PSTR("Reachable")).setBool(getReachable());
if (validPower()) { attr_list.addAttributePMEM(PSTR("Power")).setUInt(getPower()); }
int32_t light_mode = -1;
const Z_Data_Light & light = data.find<Z_Data_Light>(0);
if (&light != nullptr) {
@ -723,7 +725,7 @@ void Z_Device::jsonLightState(Z_attribute_list & attr_list) const {
attr_list.findOrCreateAttribute(PSTR("Hue")).setUInt(light.getHue());
}
}
attr_list.addAttribute(F("Light")).setInt(light_mode);
attr_list.addAttributePMEM(PSTR("Light")).setInt(light_mode);
}
}

View File

@ -1389,7 +1389,7 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) {
uint16_t read_attr_ids[len/2];
attr_list.addAttribute(F(D_CMND_ZIGBEE_CLUSTER)).setUInt(_cluster_id);
attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_CLUSTER)).setUInt(_cluster_id);
JsonGeneratorArray attr_numbers;
Z_attribute_list attr_names;
@ -1411,8 +1411,8 @@ void ZCLFrame::parseReadAttributes(Z_attribute_list& attr_list) {
}
i += 2;
}
attr_list.addAttribute(F("Read")).setStrRaw(attr_numbers.toString().c_str());
attr_list.addAttribute(F("ReadNames")).setStrRaw(attr_names.toString(true).c_str());
attr_list.addAttributePMEM(PSTR("Read")).setStrRaw(attr_numbers.toString().c_str());
attr_list.addAttributePMEM(PSTR("ReadNames")).setStrRaw(attr_names.toString(true).c_str());
// call auto-responder
autoResponder(read_attr_ids, len/2);
@ -1428,8 +1428,8 @@ void ZCLFrame::parseConfigAttributes(Z_attribute_list& attr_list) {
uint16_t attr_id = _payload.get8(i+2);
Z_attribute_list attr_config_response;
attr_config_response.addAttribute(F("Status")).setUInt(status);
attr_config_response.addAttribute(F("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str());
attr_config_response.addAttributePMEM(PSTR("Status")).setUInt(status);
attr_config_response.addAttributePMEM(PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str());
const __FlashStringHelper* attr_name = zigbeeFindAttributeById(_cluster_id, attr_id, nullptr, nullptr);
if (attr_name) {
@ -1439,7 +1439,7 @@ void ZCLFrame::parseConfigAttributes(Z_attribute_list& attr_list) {
}
}
Z_attribute &attr_1 = attr_list.addAttribute(F("ConfigResponse"));
Z_attribute &attr_1 = attr_list.addAttributePMEM(PSTR("ConfigResponse"));
attr_1.setStrRaw(attr_config_list.toString(true).c_str());
}
@ -1448,7 +1448,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
uint32_t i = 0;
uint32_t len = _payload.len();
Z_attribute &attr_root = attr_list.addAttribute(F("ReadConfig"));
Z_attribute &attr_root = attr_list.addAttributePMEM(PSTR("ReadConfig"));
Z_attribute_list attr_1;
while (len >= i + 4) {
@ -1458,7 +1458,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
Z_attribute_list attr_2;
if (direction) {
attr_2.addAttribute(F("DirectionReceived")).setBool(true);
attr_2.addAttributePMEM(PSTR("DirectionReceived")).setBool(true);
}
// find the attribute name
@ -1477,15 +1477,15 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
}
i += 4;
if (0 != status) {
attr_2.addAttribute(F("Status")).setUInt(status);
attr_2.addAttribute(F("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str());
attr_2.addAttributePMEM(PSTR("Status")).setUInt(status);
attr_2.addAttributePMEM(PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(status).c_str());
} else {
// no error, decode data
if (direction) {
// only Timeout period is present
uint16_t attr_timeout = _payload.get16(i);
i += 2;
attr_2.addAttribute(F("TimeoutPeriod")).setUInt((0xFFFF == attr_timeout) ? -1 : attr_timeout);
attr_2.addAttributePMEM(PSTR("TimeoutPeriod")).setUInt((0xFFFF == attr_timeout) ? -1 : attr_timeout);
} else {
// direction == 0, we have a data type
uint8_t attr_type = _payload.get8(i);
@ -1493,11 +1493,11 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
uint16_t attr_min_interval = _payload.get16(i+1);
uint16_t attr_max_interval = _payload.get16(i+3);
i += 5;
attr_2.addAttribute(F("MinInterval")).setUInt((0xFFFF == attr_min_interval) ? -1 : attr_min_interval);
attr_2.addAttribute(F("MaxInterval")).setUInt((0xFFFF == attr_max_interval) ? -1 : attr_max_interval);
attr_2.addAttributePMEM(PSTR("MinInterval")).setUInt((0xFFFF == attr_min_interval) ? -1 : attr_min_interval);
attr_2.addAttributePMEM(PSTR("MaxInterval")).setUInt((0xFFFF == attr_max_interval) ? -1 : attr_max_interval);
if (!attr_discrete) {
// decode Reportable Change
Z_attribute &attr_change = attr_2.addAttribute(F("ReportableChange"));
Z_attribute &attr_change = attr_2.addAttributePMEM(PSTR("ReportableChange"));
i += parseSingleAttribute(attr_change, _payload, i, attr_type);
if ((1 != multiplier) && (0 != multiplier)) {
float fval = attr_change.getFloat();
@ -1541,21 +1541,21 @@ void ZCLFrame::parseResponse(void) {
// "Device"
char s[12];
snprintf_P(s, sizeof(s), PSTR("0x%04X"), _srcaddr);
attr_list.addAttribute(F(D_JSON_ZIGBEE_DEVICE)).setStr(s);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setStr(s);
// "Name"
const char * friendlyName = zigbee_devices.getFriendlyName(_srcaddr);
if (friendlyName) {
attr_list.addAttribute(F(D_JSON_ZIGBEE_NAME)).setStr(friendlyName);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAME)).setStr(friendlyName);
}
// "Command"
snprintf_P(s, sizeof(s), PSTR("%04X!%02X"), _cluster_id, cmd);
attr_list.addAttribute(F(D_JSON_ZIGBEE_CMD)).setStr(s);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_CMD)).setStr(s);
// "Status"
attr_list.addAttribute(F(D_JSON_ZIGBEE_STATUS)).setUInt(status);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_STATUS)).setUInt(status);
// "StatusMessage"
attr_list.addAttribute(F(D_JSON_ZIGBEE_STATUS_MSG)).setStr(getZigbeeStatusMessage(status).c_str());
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_STATUS_MSG)).setStr(getZigbeeStatusMessage(status).c_str());
// Add Endpoint
attr_list.addAttribute(F(D_CMND_ZIGBEE_ENDPOINT)).setUInt(_srcendpoint);
attr_list.addAttributePMEM(PSTR(D_CMND_ZIGBEE_ENDPOINT)).setUInt(_srcendpoint);
// Add Group if non-zero
if (_groupaddr) { // TODO what about group zero
attr_list.group_id = _groupaddr;
@ -1628,11 +1628,11 @@ void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribu
}
} else if (modelId.startsWith(F("lumi.sensor_smoke"))) { // gas leak
if (0x64 == attrid) {
attr_list.addAttribute(F("SmokeDensity")).copyVal(attr);
attr_list.addAttributePMEM(PSTR("SmokeDensity")).copyVal(attr);
}
} else if (modelId.startsWith(F("lumi.sensor_natgas"))) { // gas leak
if (0x64 == attrid) {
attr_list.addAttribute(F("GasDensity")).copyVal(attr);
attr_list.addAttributePMEM(PSTR("GasDensity")).copyVal(attr);
}
} else if (modelId.startsWith(F("lumi.sensor_ht")) ||
modelId.equals(F("lumi.sens")) ||
@ -1831,7 +1831,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi;
int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi;
snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", Angle_X, Angle_Y, Angle_Z);
attr_list.addAttribute(F("AqaraAngles")).setStrRaw(temp);
attr_list.addAttributePMEM(PSTR("AqaraAngles")).setStrRaw(temp);
}
}
break;

View File

@ -201,7 +201,7 @@ void Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uin
if (BAD_SHORTADDR != shortaddr) {
zigbee_devices.getShortAddr(shortaddr).setReachable(false); // mark device as reachable
Z_attribute_list attr_list;
attr_list.addAttribute(F("Reachable")).setBool(false); // "Reachable":false
attr_list.addAttributePMEM(PSTR("Reachable")).setBool(false); // "Reachable":false
// Z_postProcessAttributes(shortaddr, endpoint, attr_list); // make sure all is updated accordingly
zigbee_devices.jsonPublishNow(shortaddr, attr_list);
}
@ -394,38 +394,38 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster,
case 0x00050004: // AddScene or RemoveScene or StoreScene
attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x);
attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str());
attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.y);
attr_list.addAttribute(PSTR("SceneId"), true).setUInt(xyz.z);
attr_list.addAttributePMEM(PSTR("GroupId")).setUInt(xyz.y);
attr_list.addAttributePMEM(PSTR("SceneId")).setUInt(xyz.z);
if (0x00050001 == cccc00mm) { // ViewScene specific
attr_list.addAttribute(PSTR("ScenePayload"), true).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes
attr_list.addAttributePMEM(PSTR("ScenePayload")).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes
}
break;
case 0x00050003: // RemoveAllScenes
attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x);
attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str());
attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.y);
attr_list.addAttributePMEM(PSTR("GroupId")).setUInt(xyz.y);
break;
case 0x00050006: // GetSceneMembership
attr_list.addAttribute(command_name, PSTR("Status")).setUInt(xyz.x);
attr_list.addAttribute(command_name, PSTR("StatusMsg")).setStr(getZigbeeStatusMessage(xyz.x).c_str());
attr_list.addAttribute(PSTR("Capacity"), true).setUInt(xyz.y);
attr_list.addAttribute(PSTR("GroupId"), true).setUInt(xyz.z);
attr_list.addAttribute(PSTR("ScenePayload"), true).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes
attr_list.addAttributePMEM(PSTR("Capacity")).setUInt(xyz.y);
attr_list.addAttributePMEM(PSTR("GroupId")).setUInt(xyz.z);
attr_list.addAttributePMEM(PSTR("ScenePayload")).setBuf(payload, 4, payload.len()-4); // remove first 4 bytes
break;
case 0x00060040: // Power Off With Effect
attr_list.addAttribute(PSTR("Power"), true).setUInt(0);
attr_list.addAttribute(PSTR("PowerEffect"), true).setUInt(xyz.x);
attr_list.addAttribute(PSTR("PowerEffectVariant"), true).setUInt(xyz.y);
attr_list.addAttributePMEM(PSTR("Power")).setUInt(0);
attr_list.addAttributePMEM(PSTR("PowerEffect")).setUInt(xyz.x);
attr_list.addAttributePMEM(PSTR("PowerEffectVariant")).setUInt(xyz.y);
break;
case 0x00060041: // Power On With Recall Global Scene
attr_list.addAttribute(PSTR("Power"), true).setUInt(1);
attr_list.addAttribute(PSTR("PowerRecallGlobalScene"), true).setBool(true);
attr_list.addAttributePMEM(PSTR("Power")).setUInt(1);
attr_list.addAttributePMEM(PSTR("PowerRecallGlobalScene")).setBool(true);
break;
case 0x00060042: // Power On With Timed Off Command
attr_list.addAttribute(PSTR("Power"), true).setUInt(1);
attr_list.addAttribute(PSTR("PowerOnlyWhenOn"), true).setUInt(xyz.x);
attr_list.addAttribute(PSTR("PowerOnTime"), true).setFloat(xyz.y / 10.0f);
attr_list.addAttribute(PSTR("PowerOffWait"), true).setFloat(xyz.z / 10.0f);
attr_list.addAttributePMEM(PSTR("Power")).setUInt(1);
attr_list.addAttributePMEM(PSTR("PowerOnlyWhenOn")).setUInt(xyz.x);
attr_list.addAttributePMEM(PSTR("PowerOnTime")).setFloat(xyz.y / 10.0f);
attr_list.addAttributePMEM(PSTR("PowerOffWait")).setFloat(xyz.z / 10.0f);
break;
case 0xEF000000 ... 0xEF0000FF: // any Tuya - Moes command
if (convertTuyaSpecificCluster(attr_list, cluster, cmd, direction, shortaddr, srcendpoint, payload)) {
@ -433,8 +433,8 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster,
}
break;
case 0xFCCC0000: // Terncy button (multi-)press
attr_list.addAttribute(PSTR("TerncyPress"), true).setUInt(xyz.y);
attr_list.addAttribute(PSTR("TerncyCount"), true).setUInt(xyz.x);
attr_list.addAttributePMEM(PSTR("TerncyPress")).setUInt(xyz.y);
attr_list.addAttributePMEM(PSTR("TerncyCount")).setUInt(xyz.x);
break;
}
} else { // general case

View File

@ -1115,13 +1115,11 @@ void CmndZbModelId(void) {
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
if (p == nullptr) {
const char * modelId = device.modelId;
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), device.shortaddr, modelId ? modelId : "");
} else {
if (p != nullptr) {
device.setModelId(p);
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), device.shortaddr, p);
}
const char * modelId = device.modelId;
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), device.shortaddr, modelId ? modelId : "");
}
//