Skip to content

Commit

Permalink
Merge branch 'development' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
arendst committed Mar 18, 2020
2 parents a3cc81b + 5a98fd4 commit dd286e5
Show file tree
Hide file tree
Showing 15 changed files with 104 additions and 286 deletions.
1 change: 1 addition & 0 deletions tasmota/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Add command ``HumOffset -10.0 .. 10.0`` to set global humidity sensor offset (#7934)
- Add Zigbee support for Hue emulation by Stefan Hadinger
- Add Dew Point to Temperature and Humidity sensors
- Change Zigbee simplification of devices probing, saving Flash and memory

### 8.1.0.10 20200227

Expand Down
1 change: 0 additions & 1 deletion tasmota/support.ino
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,6 @@ float CalcTempHumToDew(float t, float h)
t = (t - 32) / 1.8; // Celsius
}

// float gamma = log(h / 100) + 17.62 * t / (243.5 + t);
float gamma = TaylorLog(h / 100) + 17.62 * t / (243.5 + t);
float result = (243.5 * gamma / (17.62 - gamma));

Expand Down
3 changes: 0 additions & 3 deletions tasmota/xdrv_23_zigbee_0_constants.ino
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,6 @@ enum ZCL_Global_Commands {
#define ZF(s) static const char ZS_ ## s[] PROGMEM = #s;
#define Z(s) ZS_ ## s

const uint16_t Z_ProfileIds[] PROGMEM = { 0x0104, 0x0109, 0xA10E, 0xC05E };
const char Z_ProfileNames[] PROGMEM = "ZigBee Home Automation|ZigBee Smart Energy|ZigBee Green Power|ZigBee Light Link";

typedef struct Z_StatusLine {
uint32_t status; // no need to use uint8_t since it uses 32 bits anyways
const char * status_msg;
Expand Down
173 changes: 28 additions & 145 deletions tasmota/xdrv_23_zigbee_2_devices.ino
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait f

typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value);

const size_t endpoints_max = 8; // we limit to 8 endpoints

typedef struct Z_Device {
uint64_t longaddr; // 0x00 means unspecified
char * manufacturerId;
char * modelId;
char * friendlyName;
std::vector<uint32_t> endpoints; // encoded as high 16 bits is endpoint, low 16 bits is ProfileId
std::vector<uint32_t> clusters_in; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
std::vector<uint32_t> clusters_out; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
uint8_t endpoints[endpoints_max]; // static array to limit memory consumption, list of endpoints until 0x00 or end of array
// json buffer used for attribute reporting
DynamicJsonBuffer *json_buffer;
JsonObject *json;
Expand Down Expand Up @@ -81,7 +81,6 @@ typedef struct Z_Deferred {
// - shortaddr is unique if not null
// - longaddr is unique if not null
// - shortaddr and longaddr cannot be both null
// - clusters_in and clusters_out containt only endpoints listed in endpoints
class Z_Devices {
public:
Z_Devices() {};
Expand All @@ -98,20 +97,17 @@ public:

uint64_t getDeviceLongAddr(uint16_t shortaddr) const;

uint8_t findFirstEndpoint(uint16_t shortaddr) const;

// Add new device, provide ShortAddr and optional longAddr
// If it is already registered, update information, otherwise create the entry
void updateDevice(uint16_t shortaddr, uint64_t longaddr = 0);

// Add an endpoint to a device
void addEndoint(uint16_t shortaddr, uint8_t endpoint);

// Add endpoint profile
void addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t profileId);
void addEndpoint(uint16_t shortaddr, uint8_t endpoint);

// Add cluster
void addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster, bool out);

uint8_t findClusterEndpointIn(uint16_t shortaddr, uint16_t cluster);
void addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster);

void setManufId(uint16_t shortaddr, const char * str);
void setModelId(uint16_t shortaddr, const char * str);
Expand Down Expand Up @@ -175,8 +171,6 @@ public:
private:
std::vector<Z_Device*> _devices = {};
std::vector<Z_Deferred> _deferred = {}; // list of deferred calls
// std::vector<Z_Device> _devices = std::vector<Z_Device>(4);
// std::vector<Z_Deferred> _deferred = std::vector<Z_Deferred>(4); // list of deferred calls
uint32_t _saveTimer = 0;
uint8_t _seqNumber = 0; // global seqNumber if device is unknown

Expand All @@ -186,9 +180,6 @@ private:
template < typename T>
static int32_t findEndpointInVector(const std::vector<T> & vecOfElements, uint8_t element);

// find the first endpoint match for a cluster
static int32_t findClusterEndpoint(const std::vector<uint32_t> & vecOfElements, uint16_t element);

Z_Device & getShortAddr(uint16_t shortaddr); // find Device from shortAddr, creates it if does not exist
const Z_Device & getShortAddrConst(uint16_t shortaddr) const ; // find Device from shortAddr, creates it if does not exist
Z_Device & getLongAddr(uint64_t longaddr); // find Device from shortAddr, creates it if does not exist
Expand Down Expand Up @@ -226,31 +217,13 @@ int32_t Z_Devices::findEndpointInVector(const std::vector<T> & vecOfElements, u

int32_t found = 0;
for (auto &elem : vecOfElements) {
if ( ((elem >> 16) & 0xFF) == element) { return found; }
if (elem == element) { return found; }
found++;
}

return -1;
}

//
// Find the first endpoint match for a cluster, whether in or out
// Clusters are stored in the format 0x00EECCCC (EE=endpoint, CCCC=cluster number)
// In:
// _devices.clusters_in or _devices.clusters_out
// cluster number looked for
// Out:
// Index of found Endpoint_Cluster number, or -1 if not found
//
int32_t Z_Devices::findClusterEndpoint(const std::vector<uint32_t> & vecOfElements, uint16_t cluster) {
int32_t found = 0;
for (auto &elem : vecOfElements) {
if ((elem & 0xFFFF) == cluster) { return found; }
found++;
}
return -1;
}

//
// Create a new Z_Device entry in _devices. Only to be called if you are sure that no
// entry with same shortaddr or longaddr exists.
Expand All @@ -263,9 +236,7 @@ Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) {
nullptr, // ManufId
nullptr, // DeviceId
nullptr, // FriendlyName
std::vector<uint32_t>(), // at least one endpoint
std::vector<uint32_t>(), // try not to allocate if not needed
std::vector<uint32_t>(), // try not to allocate if not needed
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // endpoints
nullptr, nullptr,
shortaddr,
0, // seqNumber
Expand Down Expand Up @@ -293,13 +264,6 @@ void Z_Devices::freeDeviceEntry(Z_Device *device) {
free(device);
}

void Z_Devices::shrinkToFit(uint16_t shortaddr) {
Z_Device & device = getShortAddr(shortaddr);
device.endpoints.shrink_to_fit();
device.clusters_in.shrink_to_fit();
device.clusters_out.shrink_to_fit();
}

//
// Scan all devices to find a corresponding shortaddr
// Looks info device.shortaddr entry
Expand Down Expand Up @@ -489,67 +453,31 @@ void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
//
// Add an endpoint to a shortaddr
//
void Z_Devices::addEndoint(uint16_t shortaddr, uint8_t endpoint) {
void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
if (!shortaddr) { return; }
if (0x00 == endpoint) { return; }
uint32_t ep_profile = (endpoint << 16);
Z_Device &device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
if (findEndpointInVector(device.endpoints, endpoint) < 0) {
device.endpoints.push_back(ep_profile);
dirty();
}
}

void Z_Devices::addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t profileId) {
if (!shortaddr) { return; }
if (0x00 == endpoint) { return; }
uint32_t ep_profile = (endpoint << 16) | profileId;
Z_Device &device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
int32_t found = findEndpointInVector(device.endpoints, endpoint);
if (found < 0) {
device.endpoints.push_back(ep_profile);
dirty();
} else {
if (device.endpoints[found] != ep_profile) {
device.endpoints[found] = ep_profile;
dirty();
}
}
}

void Z_Devices::addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster, bool out) {
if (!shortaddr) { return; }
Z_Device & device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
uint32_t ep_cluster = (endpoint << 16) | cluster;
if (!out) {
if (!findInVector(device.clusters_in, ep_cluster)) {
device.clusters_in.push_back(ep_cluster);
dirty();
for (uint32_t i = 0; i < endpoints_max; i++) {
if (endpoint == device.endpoints[i]) {
return; // endpoint already there
}
} else { // out
if (!findInVector(device.clusters_out, ep_cluster)) {
device.clusters_out.push_back(ep_cluster);
if (0 == device.endpoints[i]) {
device.endpoints[i] = endpoint;
dirty();
return;
}
}
}

// Look for the best endpoint match to send a command for a specific Cluster ID
// return 0x00 if none found
uint8_t Z_Devices::findClusterEndpointIn(uint16_t shortaddr, uint16_t cluster){
int32_t short_found = findShortAddr(shortaddr);
if (short_found < 0) return 0; // avoid creating an entry if the device was never seen
Z_Device &device = getShortAddr(shortaddr);
if (&device == nullptr) { return 0; } // don't crash if not found
int32_t found = findClusterEndpoint(device.clusters_in, cluster);
if (found >= 0) {
return (device.clusters_in[found] >> 16) & 0xFF;
} else {
return 0;
}
// Find the first endpoint of the device
uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found < 0) return 0; // avoid creating an entry if the device was never seen
const Z_Device &device = devicesAt(found);

return device.endpoints[0]; // returns 0x00 if no endpoint
}

void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
Expand Down Expand Up @@ -1069,58 +997,13 @@ String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const {
if (device.manufacturerId) {
dev[F("Manufacturer")] = device.manufacturerId;
}
}

// If dump_mode == 2, dump a lot more details
if (3 <= dump_mode) {
JsonObject& dev_endpoints = dev.createNestedObject(F("Endpoints"));
for (std::vector<uint32_t>::const_iterator ite = device.endpoints.begin() ; ite != device.endpoints.end(); ++ite) {
uint32_t ep_profile = *ite;
uint8_t endpoint = (ep_profile >> 16) & 0xFF;
uint16_t profileId = ep_profile & 0xFFFF;
JsonArray& dev_endpoints = dev.createNestedArray(F("Endpoints"));
for (uint32_t i = 0; i < endpoints_max; i++) {
uint8_t endpoint = device.endpoints[i];
if (0x00 == endpoint) { break; }

snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
JsonObject& ep = dev_endpoints.createNestedObject(hex);

snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), profileId);
ep[F("ProfileId")] = hex;

int32_t found = -1;
for (uint32_t i = 0; i < sizeof(Z_ProfileIds) / sizeof(Z_ProfileIds[0]); i++) {
if (pgm_read_word(&Z_ProfileIds[i]) == profileId) {
found = i;
break;
}
}
if (found > 0) {
GetTextIndexed(hex, sizeof(hex), found, Z_ProfileNames);
ep[F("ProfileIdName")] = hex;
}

ep.createNestedArray(F("ClustersIn"));
ep.createNestedArray(F("ClustersOut"));
}

for (std::vector<uint32_t>::const_iterator itc = device.clusters_in.begin() ; itc != device.clusters_in.end(); ++itc) {
uint16_t cluster = *itc & 0xFFFF;
uint8_t endpoint = (*itc >> 16) & 0xFF;

snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
JsonArray &cluster_arr = dev_endpoints[hex][F("ClustersIn")];

snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
cluster_arr.add(hex);
}

for (std::vector<uint32_t>::const_iterator itc = device.clusters_out.begin() ; itc != device.clusters_out.end(); ++itc) {
uint16_t cluster = *itc & 0xFFFF;
uint8_t endpoint = (*itc >> 16) & 0xFF;

snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
JsonArray &cluster_arr = dev_endpoints[hex][F("ClustersOut")];

snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
cluster_arr.add(hex);
dev_endpoints.add(hex);
}
}
}
Expand Down
47 changes: 17 additions & 30 deletions tasmota/xdrv_23_zigbee_4_persistence.ino
Original file line number Diff line number Diff line change
Expand Up @@ -108,37 +108,25 @@ class SBuffer hibernateDevice(const struct Z_Device &device) {
buf.add8(0x00); // overall length, will be updated later
buf.add16(device.shortaddr);
buf.add64(device.longaddr);
uint32_t endpoints = device.endpoints.size();
if (endpoints > 254) { endpoints = 254; }
buf.add8(endpoints);

uint32_t endpoints_count = 0;
for (endpoints_count = 0; endpoints_count < endpoints_max; endpoints_count++) {
if (0x00 == device.endpoints[endpoints_count]) { break; }
}

buf.add8(endpoints_count);
// iterate on endpoints
for (std::vector<uint32_t>::const_iterator ite = device.endpoints.begin() ; ite != device.endpoints.end(); ++ite) {
uint32_t ep_profile = *ite;
uint8_t endpoint = (ep_profile >> 16) & 0xFF;
uint16_t profileId = ep_profile & 0xFFFF;
for (uint32_t i = 0; i < endpoints_max; i++) {
uint8_t endpoint = device.endpoints[i];
if (0x00 == endpoint) { break; } // stop

buf.add8(endpoint);
buf.add16(profileId);
for (std::vector<uint32_t>::const_iterator itc = device.clusters_in.begin() ; itc != device.clusters_in.end(); ++itc) {
uint16_t cluster = *itc & 0xFFFF;
uint8_t c_endpoint = (*itc >> 16) & 0xFF;

if (endpoint == c_endpoint) {
uint8_t clusterCode = toClusterCode(cluster);
if (0xFF != clusterCode) { buf.add8(clusterCode); }
}
}
buf.add8(0xFF); // end of endpoint marker
buf.add16(0x0000); // profile_id, not used anymore

for (std::vector<uint32_t>::const_iterator itc = device.clusters_out.begin() ; itc != device.clusters_out.end(); ++itc) {
uint16_t cluster = *itc & 0xFFFF;
uint8_t c_endpoint = (*itc >> 16) & 0xFF;
// removed clusters_in
buf.add8(0xFF); // end of endpoint marker

if (endpoint == c_endpoint) {
uint8_t clusterCode = toClusterCode(cluster);
if (0xFF != clusterCode) { buf.add8(clusterCode); }
}
}
// no more storage of clusters_out
buf.add8(0xFF); // end of endpoint marker
}

Expand Down Expand Up @@ -235,22 +223,21 @@ void hydrateDevices(const SBuffer &buf) {
for (uint32_t j = 0; j < endpoints; j++) {
uint8_t ep = buf_d.get8(d++);
uint16_t ep_profile = buf_d.get16(d); d += 2;
zigbee_devices.addEndointProfile(shortaddr, ep, ep_profile);
zigbee_devices.addEndpoint(shortaddr, ep);

// in clusters
while (d < dev_record_len) { // safe guard against overflow
uint8_t ep_cluster = buf_d.get8(d++);
if (0xFF == ep_cluster) { break; } // end of block
zigbee_devices.addCluster(shortaddr, ep, fromClusterCode(ep_cluster), false);
// ignore
}
// out clusters
while (d < dev_record_len) { // safe guard against overflow
uint8_t ep_cluster = buf_d.get8(d++);
if (0xFF == ep_cluster) { break; } // end of block
zigbee_devices.addCluster(shortaddr, ep, fromClusterCode(ep_cluster), true);
// ignore
}
}
zigbee_devices.shrinkToFit(shortaddr);
//AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Device 0x%04X Memory3.shrink = %d"), shortaddr, ESP.getFreeHeap());

// parse 3 strings
Expand Down
Loading

0 comments on commit dd286e5

Please sign in to comment.