Merge pull request #9144 from s-hadinger/zigbee_aug_22

Add Zigbee web gui widget for Temp/Humidity/Pressure sensors
This commit is contained in:
Theo Arends 2020-08-23 08:57:08 +02:00 committed by GitHub
commit 363b8e6b76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 239 additions and 309 deletions

View File

@ -8,6 +8,7 @@
- Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add better config corruption recovery (#9046) - Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) - Add better config corruption recovery (#9046)
- Add virtual CT for 4 channels lights, emulating a 5th channel - Add virtual CT for 4 channels lights, emulating a 5th channel
- Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113) - Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113)
- Add Zigbee web gui widget for Temp/Humidity/Pressure sensors
### 8.4.0.1 20200730 ### 8.4.0.1 20200730

View File

@ -1121,8 +1121,6 @@ enum ZCL_Global_Commands {
ZCL_DISCOVER_ATTRIBUTES_RESPONSE = 0x0d ZCL_DISCOVER_ATTRIBUTES_RESPONSE = 0x0d
}; };
#define ZF(s) static const char ZS_ ## s[] PROGMEM = #s;
#define Z(s) ZS_ ## s
#define Z_(s) Zo_ ## s #define Z_(s) Zo_ ## s
// ZDP Enumeration, see Zigbee spec 2.4.5 // ZDP Enumeration, see Zigbee spec 2.4.5

View File

@ -50,7 +50,9 @@ uint8_t Z_GetLastEndpoint(void) { return gZbLastMessage.endpoint; }
const size_t endpoints_max = 8; // we limit to 8 endpoints const size_t endpoints_max = 8; // we limit to 8 endpoints
typedef struct Z_Device { class Z_Device {
public:
uint64_t longaddr; // 0x00 means unspecified uint64_t longaddr; // 0x00 means unspecified
char * manufacturerId; char * manufacturerId;
char * modelId; char * modelId;
@ -82,9 +84,69 @@ typedef struct Z_Device {
uint16_t ct; // last CT: 153-500 | 0xFFFF not set, default 200 uint16_t ct; // last CT: 153-500 | 0xFFFF not set, default 200
uint16_t hue; // last Hue: 0..359 | 0xFFFF not set, default 0 uint16_t hue; // last Hue: 0..359 | 0xFFFF not set, default 0
uint16_t x, y; // last color [x,y] | 0xFFFF not set, default 0 uint16_t x, y; // last color [x,y] | 0xFFFF not set, default 0
uint8_t linkquality; // lqi from last message, 0xFF means unknown uint8_t lqi; // lqi from last message, 0xFF means unknown
uint8_t batterypercent; // battery percentage (0..100), 0xFF means unknwon uint8_t batterypercent; // battery percentage (0..100), 0xFF means unknwon
} Z_Device; // sensor data
int16_t temperature; // temperature in 1/10th of Celsius, 0x8000 if unknown
uint16_t pressure; // air pressure in hPa, 0xFFFF if unknown
uint8_t humidity; // humidity in percent, 0..100, 0xFF if unknown
// Constructor with all defaults
Z_Device(uint16_t _shortaddr, uint64_t _longaddr = 0x00):
longaddr(_longaddr),
manufacturerId(nullptr),
modelId(nullptr),
friendlyName(nullptr),
endpoints{ 0, 0, 0, 0, 0, 0, 0, 0 },
json_buffer(nullptr),
json(nullptr),
shortaddr(_shortaddr),
seqNumber(0),
// Hue support
zb_profile(0xFF), // no profile
power(0x02), // 0x80 = reachable, 0x01 = power on, 0x02 = power unknown
colormode(0xFF),
dimmer(0xFF),
sat(0xFF),
ct(0xFFFF),
hue(0xFFFF),
x(0xFFFF),
y(0xFFFF),
lqi(0xFF),
batterypercent(0xFF),
temperature(-0x8000),
pressure(0xFFFF),
humidity(0xFF)
{ };
inline bool valid(void) const { return BAD_SHORTADDR != shortaddr; } // is the device known, valid and found?
inline bool validLongaddr(void) const { return 0x0000 != longaddr; }
inline bool validManufacturerId(void) const { return nullptr != manufacturerId; }
inline bool validModelId(void) const { return nullptr != modelId; }
inline bool validFriendlyName(void) const { return nullptr != friendlyName; }
inline bool validPower(void) const { return 0x00 == (power & 0x02); }
inline bool validColormode(void) const { return 0xFF != colormode; }
inline bool validDimmer(void) const { return 0xFF != dimmer; }
inline bool validSat(void) const { return 0xFF != sat; }
inline bool validCT(void) const { return 0xFFFF != ct; }
inline bool validHue(void) const { return 0xFFFF != hue; }
inline bool validX(void) const { return 0xFFFF != x; }
inline bool validY(void) const { return 0xFFFF != y; }
inline bool validLqi(void) const { return 0xFF != lqi; }
inline bool validBatteryPercent(void) const { return 0xFF != batterypercent; }
inline bool validTemperature(void) const { return -0x8000 != temperature; }
inline bool validPressure(void) const { return 0xFFFF != pressure; }
inline bool validHumidity(void) const { return 0xFF != humidity; }
inline void setReachable(bool reachable) { bitWrite(power, 7, reachable); }
inline bool getReachable(void) const { return bitRead(power, 7); }
inline void setPower(bool power_on) { bitWrite(power, 0, power_on); bitWrite(power, 1, false); }
inline bool getPower(void) const { return bitRead(power, 0); }
};
/*********************************************************************************************\ /*********************************************************************************************\
* Structures for deferred callbacks * Structures for deferred callbacks
@ -136,11 +198,17 @@ public:
// - 0x0000 = not found // - 0x0000 = not found
// - BAD_SHORTADDR = bad parameter // - BAD_SHORTADDR = bad parameter
// - 0x<shortaddr> = the device's short address // - 0x<shortaddr> = the device's short address
uint16_t isKnownShortAddr(uint16_t shortaddr) const;
uint16_t isKnownLongAddr(uint64_t longaddr) const; uint16_t isKnownLongAddr(uint64_t longaddr) const;
uint16_t isKnownIndex(uint32_t index) const; uint16_t isKnownIndex(uint32_t index) const;
uint16_t isKnownFriendlyName(const char * name) const; uint16_t isKnownFriendlyName(const char * name) const;
const Z_Device & findShortAddr(uint16_t shortaddr) const;
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
int32_t findLongAddr(uint64_t longaddr) const;
int32_t findFriendlyName(const char * name) const;
uint64_t getDeviceLongAddr(uint16_t shortaddr) const; uint64_t getDeviceLongAddr(uint16_t shortaddr) const;
uint8_t findFirstEndpoint(uint16_t shortaddr) const; uint8_t findFirstEndpoint(uint16_t shortaddr) const;
@ -157,12 +225,19 @@ public:
void setManufId(uint16_t shortaddr, const char * str); void setManufId(uint16_t shortaddr, const char * str);
void setModelId(uint16_t shortaddr, const char * str); void setModelId(uint16_t shortaddr, const char * str);
void setFriendlyName(uint16_t shortaddr, const char * str); void setFriendlyName(uint16_t shortaddr, const char * str);
const char * getFriendlyName(uint16_t shortaddr) const; inline const char * getFriendlyName(uint16_t shortaddr) const {
const char * getModelId(uint16_t shortaddr) const; return findShortAddr(shortaddr).friendlyName;
const char * getManufacturerId(uint16_t shortaddr) const; }
inline const char * getModelId(uint16_t shortaddr) const {
return findShortAddr(shortaddr).modelId;
}
inline const char * getManufacturerId(uint16_t shortaddr) const{
return findShortAddr(shortaddr).manufacturerId;
}
void setReachable(uint16_t shortaddr, bool reachable); void setReachable(uint16_t shortaddr, bool reachable);
void setLQI(uint16_t shortaddr, uint8_t lqi); void setLQI(uint16_t shortaddr, uint8_t lqi);
uint8_t getLQI(uint16_t shortaddr) const; // uint8_t getLQI(uint16_t shortaddr) const;
void setBatteryPercent(uint16_t shortaddr, uint8_t bp); void setBatteryPercent(uint16_t shortaddr, uint8_t bp);
uint8_t getBatteryPercent(uint16_t shortaddr) const; uint8_t getBatteryPercent(uint16_t shortaddr) const;
@ -183,18 +258,6 @@ public:
int8_t getHueBulbtype(uint16_t shortaddr) const ; int8_t getHueBulbtype(uint16_t shortaddr) const ;
void hideHueBulb(uint16_t shortaddr, bool hidden); void hideHueBulb(uint16_t shortaddr, bool hidden);
bool isHueBulbHidden(uint16_t shortaddr) const ; bool isHueBulbHidden(uint16_t shortaddr) const ;
void updateHueState(uint16_t shortaddr,
const bool *power, const uint8_t *colormode,
const uint8_t *dimmer, const uint8_t *sat,
const uint16_t *ct, const uint16_t *hue,
const uint16_t *x, const uint16_t *y,
const bool *reachable);
bool getHueState(uint16_t shortaddr,
bool *power, uint8_t *colormode,
uint8_t *dimmer, uint8_t *sat,
uint16_t *ct, uint16_t *hue,
uint16_t *x, uint16_t *y,
bool *reachable) const ;
// Timers // Timers
void resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category); void resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category);
@ -234,20 +297,14 @@ private:
uint32_t _saveTimer = 0; uint32_t _saveTimer = 0;
uint8_t _seqNumber = 0; // global seqNumber if device is unknown uint8_t _seqNumber = 0; // global seqNumber if device is unknown
// Following device is used represent the unknown device, with all defaults
// Any find() function will not return Null, instead it will return this instance
const Z_Device device_unk = Z_Device(BAD_SHORTADDR);
template < typename T> template < typename T>
static bool findInVector(const std::vector<T> & vecOfElements, const T & element); static bool findInVector(const std::vector<T> & vecOfElements, const T & element);
template < typename T> int32_t findShortAddrIdx(uint16_t shortaddr) const;
static int32_t findEndpointInVector(const std::vector<T> & vecOfElements, uint8_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
int32_t findShortAddr(uint16_t shortaddr) const;
int32_t findLongAddr(uint64_t longaddr) const;
int32_t findFriendlyName(const char * name) const;
// Create a new entry in the devices list - must be called if it is sure it does not already exist // Create a new entry in the devices list - must be called if it is sure it does not already exist
Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0); Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0);
void freeDeviceEntry(Z_Device *device); void freeDeviceEntry(Z_Device *device);
@ -283,47 +340,13 @@ bool Z_Devices::findInVector(const std::vector<T> & vecOfElements, const T & e
} }
} }
template < typename T>
int32_t Z_Devices::findEndpointInVector(const std::vector<T> & vecOfElements, uint8_t element) {
// Find given element in vector
int32_t found = 0;
for (auto &elem : vecOfElements) {
if (elem == element) { return found; }
found++;
}
return -1;
}
// //
// Create a new Z_Device entry in _devices. Only to be called if you are sure that no // 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. // entry with same shortaddr or longaddr exists.
// //
Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) { Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) {
if ((BAD_SHORTADDR == shortaddr) && !longaddr) { return *(Z_Device*) nullptr; } // it is not legal to create this entry if ((BAD_SHORTADDR == shortaddr) && !longaddr) { return (Z_Device&) device_unk; } // it is not legal to create this entry
//Z_Device* device_alloc = (Z_Device*) malloc(sizeof(Z_Device)); Z_Device * device_alloc = new Z_Device(shortaddr, longaddr);
Z_Device* device_alloc = new Z_Device{
longaddr,
nullptr, // ManufId
nullptr, // DeviceId
nullptr, // FriendlyName
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // endpoints
nullptr, nullptr,
shortaddr,
0, // seqNumber
// Hue support
0xFF, // no Hue support
0x80, // power off + reachable
0xFF, // colormode
0xFF, // dimmer
0xFF, // sat
0xFFFF, // ct
0xFFFF, // hue
0xFFFF, 0xFFFF, // x, y
0xFF, // lqi, 0xFF = unknown
0xFF // battery percentage x 2, 0xFF means unknown
};
device_alloc->json_buffer = new DynamicJsonBuffer(16); device_alloc->json_buffer = new DynamicJsonBuffer(16);
_devices.push_back(device_alloc); _devices.push_back(device_alloc);
@ -346,7 +369,7 @@ void Z_Devices::freeDeviceEntry(Z_Device *device) {
// Out: // Out:
// index in _devices of entry, -1 if not found // index in _devices of entry, -1 if not found
// //
int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const { int32_t Z_Devices::findShortAddrIdx(uint16_t shortaddr) const {
if (BAD_SHORTADDR == shortaddr) { return -1; } // does not make sense to look for BAD_SHORTADDR shortaddr (broadcast) if (BAD_SHORTADDR == shortaddr) { return -1; } // does not make sense to look for BAD_SHORTADDR shortaddr (broadcast)
int32_t found = 0; int32_t found = 0;
for (auto &elem : _devices) { for (auto &elem : _devices) {
@ -355,6 +378,12 @@ int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const {
} }
return -1; return -1;
} }
const Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) const {
for (auto &elem : _devices) {
if (elem->shortaddr == shortaddr) { return *elem; }
}
return device_unk;
}
// //
// Scan all devices to find a corresponding longaddr // Scan all devices to find a corresponding longaddr
// Looks info device.longaddr entry // Looks info device.longaddr entry
@ -395,16 +424,6 @@ int32_t Z_Devices::findFriendlyName(const char * name) const {
return -1; return -1;
} }
// Probe if device is already known but don't create any entry
uint16_t Z_Devices::isKnownShortAddr(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
return shortaddr;
} else {
return BAD_SHORTADDR; // unknown
}
}
uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const { uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const {
int32_t found = findLongAddr(longaddr); int32_t found = findLongAddr(longaddr);
if (found >= 0) { if (found >= 0) {
@ -436,16 +455,15 @@ uint16_t Z_Devices::isKnownFriendlyName(const char * name) const {
} }
uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const { uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const {
const Z_Device &device = getShortAddrConst(shortaddr); return getShortAddrConst(shortaddr).longaddr; // if unknown, it reverts to the Unknown device and longaddr is 0x00
return (&device != nullptr) ? device.longaddr : 0;
} }
// //
// We have a seen a shortaddr on the network, get the corresponding device object // We have a seen a shortaddr on the network, get the corresponding device object
// //
Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) { Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
if (BAD_SHORTADDR == shortaddr) { return *(Z_Device*) nullptr; } // this is not legal if (BAD_SHORTADDR == shortaddr) { return (Z_Device&) device_unk; } // this is not legal
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddrIdx(shortaddr);
if (found >= 0) { if (found >= 0) {
return *(_devices[found]); return *(_devices[found]);
} }
@ -454,17 +472,16 @@ Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
} }
// Same version but Const // Same version but Const
const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const { const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const {
if (BAD_SHORTADDR == shortaddr) { return *(Z_Device*) nullptr; } // this is not legal int32_t found = findShortAddrIdx(shortaddr);
int32_t found = findShortAddr(shortaddr);
if (found >= 0) { if (found >= 0) {
return *(_devices[found]); return *(_devices[found]);
} }
return *((Z_Device*)nullptr); return device_unk;
} }
// find the Device object by its longaddr (unique key if not null) // find the Device object by its longaddr (unique key if not null)
Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) { Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) {
if (!longaddr) { return *(Z_Device*) nullptr; } if (!longaddr) { return (Z_Device&) device_unk; }
int32_t found = findLongAddr(longaddr); int32_t found = findLongAddr(longaddr);
if (found > 0) { if (found > 0) {
return *(_devices[found]); return *(_devices[found]);
@ -474,7 +491,7 @@ Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) {
// Remove device from list, return true if it was known, false if it was not recorded // Remove device from list, return true if it was known, false if it was not recorded
bool Z_Devices::removeDevice(uint16_t shortaddr) { bool Z_Devices::removeDevice(uint16_t shortaddr) {
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddrIdx(shortaddr);
if (found >= 0) { if (found >= 0) {
freeDeviceEntry(_devices.at(found)); freeDeviceEntry(_devices.at(found));
_devices.erase(_devices.begin() + found); _devices.erase(_devices.begin() + found);
@ -490,7 +507,7 @@ bool Z_Devices::removeDevice(uint16_t shortaddr) {
// shortaddr // shortaddr
// longaddr (both can't be null at the same time) // longaddr (both can't be null at the same time)
void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) { void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
int32_t s_found = findShortAddr(shortaddr); // is there already a shortaddr entry int32_t s_found = findShortAddrIdx(shortaddr); // is there already a shortaddr entry
int32_t l_found = findLongAddr(longaddr); // is there already a longaddr entry int32_t l_found = findLongAddr(longaddr); // is there already a longaddr entry
if ((s_found >= 0) && (l_found >= 0)) { // both shortaddr and longaddr are already registered if ((s_found >= 0) && (l_found >= 0)) { // both shortaddr and longaddr are already registered
@ -525,8 +542,6 @@ void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
// //
void Z_Devices::clearEndpoints(uint16_t shortaddr) { void Z_Devices::clearEndpoints(uint16_t shortaddr) {
Z_Device &device = getShortAddr(shortaddr); Z_Device &device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
for (uint32_t i = 0; i < endpoints_max; i++) { for (uint32_t i = 0; i < endpoints_max; i++) {
device.endpoints[i] = 0; device.endpoints[i] = 0;
// no dirty here because it doesn't make sense to store it, does it? // no dirty here because it doesn't make sense to store it, does it?
@ -539,7 +554,6 @@ void Z_Devices::clearEndpoints(uint16_t shortaddr) {
void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) { void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
if (0x00 == endpoint) { return; } if (0x00 == endpoint) { return; }
Z_Device &device = getShortAddr(shortaddr); Z_Device &device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
for (uint32_t i = 0; i < endpoints_max; i++) { for (uint32_t i = 0; i < endpoints_max; i++) {
if (endpoint == device.endpoints[i]) { if (endpoint == device.endpoints[i]) {
@ -558,7 +572,7 @@ void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
// //
uint32_t Z_Devices::countEndpoints(uint16_t shortaddr) const { uint32_t Z_Devices::countEndpoints(uint16_t shortaddr) const {
uint32_t count_ep = 0; uint32_t count_ep = 0;
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddrIdx(shortaddr);
if (found < 0) return 0; // avoid creating an entry if the device was never seen if (found < 0) return 0; // avoid creating an entry if the device was never seen
const Z_Device &device = devicesAt(found); const Z_Device &device = devicesAt(found);
@ -574,11 +588,7 @@ uint32_t Z_Devices::countEndpoints(uint16_t shortaddr) const {
uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const { uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const {
// When in router of end-device mode, the coordinator was not probed, in this case always talk to endpoint 1 // When in router of end-device mode, the coordinator was not probed, in this case always talk to endpoint 1
if (0x0000 == shortaddr) { return 1; } if (0x0000 == shortaddr) { return 1; }
int32_t found = findShortAddr(shortaddr); return findShortAddr(shortaddr).endpoints[0]; // returns 0x00 if no endpoint
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::setStringAttribute(char*& attr, const char * str) { void Z_Devices::setStringAttribute(char*& attr, const char * str) {
@ -613,94 +623,34 @@ void Z_Devices::setStringAttribute(char*& attr, const char * str) {
// - Any actual change in ManufId (i.e. setting a different value) triggers a `dirty()` and saving to Flash // - Any actual change in ManufId (i.e. setting a different value) triggers a `dirty()` and saving to Flash
// //
void Z_Devices::setManufId(uint16_t shortaddr, const char * str) { void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
Z_Device & device = getShortAddr(shortaddr); setStringAttribute(getShortAddr(shortaddr).manufacturerId, str);
if (&device == nullptr) { return; } // don't crash if not found
setStringAttribute(device.manufacturerId, str);
} }
void Z_Devices::setModelId(uint16_t shortaddr, const char * str) { void Z_Devices::setModelId(uint16_t shortaddr, const char * str) {
Z_Device & device = getShortAddr(shortaddr); setStringAttribute(getShortAddr(shortaddr).modelId, str);
if (&device == nullptr) { return; } // don't crash if not found
setStringAttribute(device.modelId, str);
} }
void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) { void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) {
Z_Device & device = getShortAddr(shortaddr); setStringAttribute(getShortAddr(shortaddr).friendlyName, str);
if (&device == nullptr) { return; } // don't crash if not found
setStringAttribute(device.friendlyName, str);
} }
const char * Z_Devices::getFriendlyName(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device & device = devicesAt(found);
return device.friendlyName;
}
return nullptr;
}
const char * Z_Devices::getModelId(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device & device = devicesAt(found);
return device.modelId;
}
return nullptr;
}
const char * Z_Devices::getManufacturerId(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device & device = devicesAt(found);
return device.manufacturerId;
}
return nullptr;
}
void Z_Devices::setReachable(uint16_t shortaddr, bool reachable) { void Z_Devices::setReachable(uint16_t shortaddr, bool reachable) {
Z_Device & device = getShortAddr(shortaddr); getShortAddr(shortaddr).setReachable(reachable);
if (&device == nullptr) { return; } // don't crash if not found
bitWrite(device.power, 7, reachable);
} }
void Z_Devices::setLQI(uint16_t shortaddr, uint8_t lqi) { void Z_Devices::setLQI(uint16_t shortaddr, uint8_t lqi) {
if (shortaddr == localShortAddr) { return; } if (shortaddr == localShortAddr) { return; }
Z_Device & device = getShortAddr(shortaddr); getShortAddr(shortaddr).lqi = lqi;
if (&device == nullptr) { return; } // don't crash if not found
device.linkquality = lqi;
}
uint8_t Z_Devices::getLQI(uint16_t shortaddr) const {
if (shortaddr == localShortAddr) { return 0xFF; }
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device & device = devicesAt(found);
return device.linkquality;
}
return 0xFF;
} }
void Z_Devices::setBatteryPercent(uint16_t shortaddr, uint8_t bp) { void Z_Devices::setBatteryPercent(uint16_t shortaddr, uint8_t bp) {
Z_Device & device = getShortAddr(shortaddr); getShortAddr(shortaddr).batterypercent = bp;
if (&device == nullptr) { return; } // don't crash if not found
device.batterypercent = bp;
}
uint8_t Z_Devices::getBatteryPercent(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device & device = devicesAt(found);
return device.batterypercent;
}
return 0xFF;
} }
// get the next sequance number for the device, or use the global seq number if device is unknown // get the next sequance number for the device, or use the global seq number if device is unknown
uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) { uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) {
int32_t short_found = findShortAddr(shortaddr); int32_t short_found = findShortAddrIdx(shortaddr);
if (short_found >= 0) { if (short_found >= 0) {
Z_Device &device = getShortAddr(shortaddr); Z_Device &device = getShortAddr(shortaddr);
device.seqNumber += 1; device.seqNumber += 1;
@ -732,7 +682,7 @@ void Z_Devices::updateZbProfile(uint16_t shortaddr) {
{ {
uint32_t channels = zb_profile & 0x07; uint32_t channels = zb_profile & 0x07;
// depending on the bulb type, the default parameters from unknown to credible defaults // depending on the bulb type, the default parameters from unknown to credible defaults
if (0xFF == device.power) { device.power = 0; } if (!device.validPower()) { device.setPower(false); }
if (1 <= channels) { if (1 <= channels) {
if (0xFF == device.dimmer) { device.dimmer = 0; } if (0xFF == device.dimmer) { device.dimmer = 0; }
} }
@ -754,12 +704,7 @@ void Z_Devices::updateZbProfile(uint16_t shortaddr) {
// Returns the device profile or 0xFF if the device or profile is unknown // Returns the device profile or 0xFF if the device or profile is unknown
uint8_t Z_Devices::getZbProfile(uint16_t shortaddr) const { uint8_t Z_Devices::getZbProfile(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr); return findShortAddr(shortaddr).zb_profile;
if (found >= 0) {
return _devices[found]->zb_profile;
} else {
return 0xFF; // Hue not activated
}
} }
// Hue support // Hue support
@ -793,7 +738,7 @@ void Z_Devices::hideHueBulb(uint16_t shortaddr, bool hidden) {
} }
// true if device is not knwon or not a bulb - it wouldn't make sense to publish a non-bulb // true if device is not knwon or not a bulb - it wouldn't make sense to publish a non-bulb
bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const { bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddrIdx(shortaddr);
if (found >= 0) { if (found >= 0) {
uint8_t zb_profile = _devices[found]->zb_profile; uint8_t zb_profile = _devices[found]->zb_profile;
if (0x00 == (zb_profile & 0xF0)) { if (0x00 == (zb_profile & 0xF0)) {
@ -804,50 +749,6 @@ bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const {
return true; // Fallback - Device is considered as hidden return true; // Fallback - Device is considered as hidden
} }
// Hue support
void Z_Devices::updateHueState(uint16_t shortaddr,
const bool *power, const uint8_t *colormode,
const uint8_t *dimmer, const uint8_t *sat,
const uint16_t *ct, const uint16_t *hue,
const uint16_t *x, const uint16_t *y,
const bool *reachable) {
Z_Device &device = getShortAddr(shortaddr);
if (power) { bitWrite(device.power, 0, *power); }
if (colormode){ device.colormode = *colormode; }
if (dimmer) { device.dimmer = *dimmer; }
if (sat) { device.sat = *sat; }
if (ct) { device.ct = *ct; }
if (hue) { device.hue = *hue; }
if (x) { device.x = *x; }
if (y) { device.y = *y; }
if (reachable){ bitWrite(device.power, 7, *reachable); }
}
// return true if ok
bool Z_Devices::getHueState(uint16_t shortaddr,
bool *power, uint8_t *colormode,
uint8_t *dimmer, uint8_t *sat,
uint16_t *ct, uint16_t *hue,
uint16_t *x, uint16_t *y,
bool *reachable) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
const Z_Device &device = *(_devices[found]);
if (power) { *power = bitRead(device.power, 0); }
if (colormode){ *colormode = device.colormode; }
if (dimmer) { *dimmer = device.dimmer; }
if (sat) { *sat = device.sat; }
if (ct) { *ct = device.ct; }
if (hue) { *hue = device.hue; }
if (x) { *x = device.x; }
if (y) { *y = device.y; }
if (reachable){ *reachable = bitRead(device.power, 7); }
return true;
} else {
return false;
}
}
// Deferred actions // Deferred actions
// Parse for a specific category, of all deferred for a device if category == 0xFF // Parse for a specific category, of all deferred for a device if category == 0xFF
void Z_Devices::resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category) { void Z_Devices::resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category) {
@ -907,8 +808,6 @@ void Z_Devices::runTimer(void) {
// Clear the JSON buffer for coalesced and deferred attributes // Clear the JSON buffer for coalesced and deferred attributes
void Z_Devices::jsonClear(uint16_t shortaddr) { void Z_Devices::jsonClear(uint16_t shortaddr) {
Z_Device & device = getShortAddr(shortaddr); Z_Device & device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
device.json = nullptr; device.json = nullptr;
device.json_buffer->clear(); device.json_buffer->clear();
} }
@ -961,7 +860,6 @@ void CopyJsonObject(JsonObject &to, const JsonObject &from) {
// false - new attributes can be safely added // false - new attributes can be safely added
bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) { bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) {
Z_Device & device = getShortAddr(shortaddr); Z_Device & device = getShortAddr(shortaddr);
if (&device == nullptr) { return false; } // don't crash if not found
if (&values == nullptr) { return false; } if (&values == nullptr) { return false; }
if (nullptr == device.json) { if (nullptr == device.json) {
@ -1005,7 +903,6 @@ bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) {
void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) { void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) {
Z_Device & device = getShortAddr(shortaddr); Z_Device & device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found
if (&values == nullptr) { return; } if (&values == nullptr) { return; }
if (nullptr == device.json) { if (nullptr == device.json) {
@ -1026,16 +923,14 @@ void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) {
} }
const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) { const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) {
Z_Device & device = getShortAddr(shortaddr); return getShortAddr(shortaddr).json;
if (&device == nullptr) { return nullptr; } // don't crash if not found
return device.json;
} }
void Z_Devices::jsonPublishFlush(uint16_t shortaddr) { void Z_Devices::jsonPublishFlush(uint16_t shortaddr) {
Z_Device & device = getShortAddr(shortaddr); Z_Device & device = getShortAddr(shortaddr);
if (&device == nullptr) { return; } // don't crash if not found if (!device.valid()) { return; } // safeguard
JsonObject & json = *device.json; JsonObject & json = *device.json;
if (&json == nullptr) { return; } // abort if nothing in buffer if (&json == nullptr) { return; } // abort if nothing in buffer
const char * fname = zigbee_devices.getFriendlyName(shortaddr); const char * fname = zigbee_devices.getFriendlyName(shortaddr);
bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname?
@ -1111,7 +1006,7 @@ uint16_t Z_Devices::parseDeviceParam(const char * param, bool short_must_be_know
// expect a short address // expect a short address
shortaddr = strtoull(dataBuf, nullptr, 0); shortaddr = strtoull(dataBuf, nullptr, 0);
if (short_must_be_known) { if (short_must_be_known) {
shortaddr = zigbee_devices.isKnownShortAddr(shortaddr); shortaddr = zigbee_devices.findShortAddr(shortaddr).shortaddr; // if not found, it reverts to the unknown_device with address BAD_SHORTADDR
} }
// else we don't check if it's already registered to force unregistered devices // else we don't check if it's already registered to force unregistered devices
} else { } else {
@ -1133,7 +1028,7 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
JsonObject& json = jsonBuffer.createObject(); JsonObject& json = jsonBuffer.createObject();
char hex[8]; char hex[8];
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddrIdx(shortaddr);
if (found >= 0) { if (found >= 0) {
const Z_Device & device = devicesAt(found); const Z_Device & device = devicesAt(found);
const char * fname = getFriendlyName(shortaddr); const char * fname = getFriendlyName(shortaddr);
@ -1153,15 +1048,15 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
// expose the last known status of the bulb, for Hue integration // expose the last known status of the bulb, for Hue integration
dev[F(D_JSON_ZIGBEE_LIGHT)] = getHueBulbtype(shortaddr); // sign extend, 0xFF changed as -1 dev[F(D_JSON_ZIGBEE_LIGHT)] = getHueBulbtype(shortaddr); // sign extend, 0xFF changed as -1
// dump all known values // dump all known values
dev[F("Reachable")] = bitRead(device.power, 7); // TODO TODO dev[F("Reachable")] = device.getReachable(); // TODO TODO
if (0xFF != device.power) { dev[F("Power")] = bitRead(device.power, 0); } if (device.validPower()) { dev[F("Power")] = device.getPower(); }
if (0xFF != device.dimmer) { dev[F("Dimmer")] = device.dimmer; } if (device.validDimmer()) { dev[F("Dimmer")] = device.dimmer; }
if (0xFF != device.colormode) { dev[F("Colormode")] = device.colormode; } if (device.validColormode()) { dev[F("Colormode")] = device.colormode; }
if (0xFFFF != device.ct) { dev[F("CT")] = device.ct; } if (device.validCT()) { dev[F("CT")] = device.ct; }
if (0xFF != device.sat) { dev[F("Sat")] = device.sat; } if (device.validSat()) { dev[F("Sat")] = device.sat; }
if (0xFFFF != device.hue) { dev[F("Hue")] = device.hue; } if (device.validHue()) { dev[F("Hue")] = device.hue; }
if (0xFFFF != device.x) { dev[F("X")] = device.x; } if (device.validX()) { dev[F("X")] = device.x; }
if (0xFFFF != device.y) { dev[F("Y")] = device.y; } if (device.validY()) { dev[F("Y")] = device.y; }
} }
String payload = ""; String payload = "";

View File

@ -36,7 +36,17 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
String light_status = ""; String light_status = "";
uint32_t echo_gen = findEchoGeneration(); // 1 for 1st gen =+ Echo Dot 2nd gen, 2 for 2nd gen and above uint32_t echo_gen = findEchoGeneration(); // 1 for 1st gen =+ Echo Dot 2nd gen, 2 for 2nd gen and above
zigbee_devices.getHueState(shortaddr, &power, &colormode, &bri, &sat, &ct, &hue, &x, &y, &reachable); const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
// TODO TODO check also validity
bri = device.dimmer;
power = device.getPower();
colormode = device.colormode;
sat = device.sat;
ct = device.ct;
hue = device.hue;
x = device.x;
y = device.y;
reachable = device.getReachable();
if (bri > 254) bri = 254; // Philips Hue bri is between 1 and 254 if (bri > 254) bri = 254; // Philips Hue bri is between 1 and 254
if (bri < 1) bri = 1; if (bri < 1) bri = 1;
@ -78,9 +88,10 @@ void HueLightStatus2Zigbee(uint16_t shortaddr, String *response)
const size_t buf_size = 300; const size_t buf_size = 300;
char * buf = (char*) malloc(buf_size); char * buf = (char*) malloc(buf_size);
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
const char * modelId = zigbee_devices.getModelId(shortaddr); const char * friendlyName = device.friendlyName;
const char * manufacturerId = zigbee_devices.getManufacturerId(shortaddr); const char * modelId = device.modelId;
const char * manufacturerId = device.manufacturerId;
char shortaddrname[8]; char shortaddrname[8];
snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr); snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr);
@ -137,7 +148,7 @@ void ZigbeeHueGroups(String * lights) {
// Power On/Off // Power On/Off
void ZigbeeHuePower(uint16_t shortaddr, bool power) { void ZigbeeHuePower(uint16_t shortaddr, bool power) {
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, ""); zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, "");
zigbee_devices.updateHueState(shortaddr, &power, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); zigbee_devices.getShortAddr(shortaddr).setPower(power);
} }
// Dimmer // Dimmer
@ -146,7 +157,7 @@ void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
char param[8]; char param[8];
snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer); snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer);
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param); zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param);
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, &dimmer, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); zigbee_devices.getShortAddr(shortaddr).dimmer = dimmer;
} }
// CT // CT
@ -157,7 +168,9 @@ void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8); snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8);
uint8_t colormode = 2; // "ct" uint8_t colormode = 2; // "ct"
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param); zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param);
zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr, &ct, nullptr, nullptr, nullptr, nullptr); Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
device.colormode = colormode;
device.ct = ct;
} }
// XY // XY
@ -168,7 +181,10 @@ void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) {
snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8); snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8);
uint8_t colormode = 1; // "xy" uint8_t colormode = 1; // "xy"
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param); zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param);
zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr, nullptr, nullptr, &x, &y, nullptr); Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
device.colormode = colormode;
device.x = x;
device.y = y;
} }
// HueSat // HueSat
@ -179,7 +195,10 @@ void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) {
snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat); snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat);
uint8_t colormode = 0; // "hs" uint8_t colormode = 0; // "hs"
zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param); zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param);
zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, &sat, nullptr, &hue, nullptr, nullptr, nullptr); Z_Device device = zigbee_devices.getShortAddr(shortaddr);
device.colormode = colormode;
device.sat = sat;
device.hue = hue;
} }
void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) { void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) {

View File

@ -445,7 +445,7 @@ const char Z_strings[] PROGMEM =
"AddScene" "\x00" "AddScene" "\x00"
"xxyyyyzz" "\x00" "xxyyyyzz" "\x00"
"StoreScene" "\x00" "StoreScene" "\x00"
"\x00"; ;
enum Z_offsets { enum Z_offsets {

View File

@ -626,6 +626,7 @@ public:
void parseResponse(void); void parseResponse(void);
void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0); void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0);
void postProcessAttributes(uint16_t shortaddr, JsonObject& json); void postProcessAttributes(uint16_t shortaddr, JsonObject& json);
void updateInternalAttributes(uint16_t shortaddr, JsonObject& json);
inline void setGroupId(uint16_t groupid) { inline void setGroupId(uint16_t groupid) {
_groupaddr = groupid; _groupaddr = groupid;
@ -1224,7 +1225,7 @@ int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu
// Aqara Cube // Aqara Cube
int32_t Z_AqaraCubeFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { int32_t Z_AqaraCubeFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) {
const char * modelId_c = zigbee_devices.getModelId(shortaddr); // null if unknown const char * modelId_c = zigbee_devices.findShortAddr(shortaddr).modelId; // null if unknown
String modelId((char*) modelId_c); String modelId((char*) modelId_c);
if (modelId.startsWith(F("lumi.sensor_cube"))) { // only for Aqara cube if (modelId.startsWith(F("lumi.sensor_cube"))) { // only for Aqara cube
@ -1487,6 +1488,24 @@ int32_t Z_ApplyConverter(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObje
return 1; // Fix GCC 10.1 warning return 1; // Fix GCC 10.1 warning
} }
// Scan all the final attributes and update any internal representation like sensors
void ZCLFrame::updateInternalAttributes(uint16_t shortaddr, JsonObject& json) {
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
for (auto kv : json) {
String key_string = kv.key;
const char * key = key_string.c_str();
JsonVariant& value = kv.value;
if (key_string.equalsIgnoreCase(F("Temperature"))) {
device.temperature = value.as<float>() * 10 + 0.5f;
} else if (key_string.equalsIgnoreCase(F("Humidity"))) {
device.humidity = value.as<float>() + 0.5f;
} else if (key_string.equalsIgnoreCase(F("Pressure"))) {
device.pressure = value.as<float>() + 0.5f;
}
}
}
void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
// source endpoint // source endpoint
uint8_t src_ep = _srcendpoint; uint8_t src_ep = _srcendpoint;
@ -1509,40 +1528,26 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
suffix = strtoul(delimiter2+1, nullptr, 10); suffix = strtoul(delimiter2+1, nullptr, 10);
} }
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
uint16_t val16 = value; // call converter from JSonVariant to int only once
// see if we need to update the Hue bulb status // see if we need to update the Hue bulb status
if ((cluster == 0x0006) && ((attribute == 0x0000) || (attribute == 0x8000))) { if ((cluster == 0x0006) && ((attribute == 0x0000) || (attribute == 0x8000))) {
bool power = value; bool power = value;
zigbee_devices.updateHueState(shortaddr, &power, nullptr, nullptr, nullptr, device.setPower(power);
nullptr, nullptr, nullptr, nullptr, nullptr);
} else if ((cluster == 0x0008) && (attribute == 0x0000)) { } else if ((cluster == 0x0008) && (attribute == 0x0000)) {
uint8_t dimmer = value; device.dimmer = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, &dimmer, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
} else if ((cluster == 0x0300) && (attribute == 0x0000)) { } else if ((cluster == 0x0300) && (attribute == 0x0000)) {
uint16_t hue8 = value; device.hue = changeUIntScale(val16, 0, 254, 0, 360); // change range from 0..254 to 0..360
uint16_t hue = changeUIntScale(hue8, 0, 254, 0, 360); // change range from 0..254 to 0..360
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
nullptr, &hue, nullptr, nullptr, nullptr);
} else if ((cluster == 0x0300) && (attribute == 0x0001)) { } else if ((cluster == 0x0300) && (attribute == 0x0001)) {
uint8_t sat = value; device.sat = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, &sat,
nullptr, nullptr, nullptr, nullptr, nullptr);
} else if ((cluster == 0x0300) && (attribute == 0x0003)) { } else if ((cluster == 0x0300) && (attribute == 0x0003)) {
uint16_t x = value; device.x = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, &x, nullptr, nullptr);
} else if ((cluster == 0x0300) && (attribute == 0x0004)) { } else if ((cluster == 0x0300) && (attribute == 0x0004)) {
uint16_t y = value; device.y = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, &y, nullptr), nullptr;
} else if ((cluster == 0x0300) && (attribute == 0x0007)) { } else if ((cluster == 0x0300) && (attribute == 0x0007)) {
uint16_t ct = value; device.ct = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
&ct, nullptr, nullptr, nullptr, nullptr);
} else if ((cluster == 0x0300) && (attribute == 0x0008)) { } else if ((cluster == 0x0300) && (attribute == 0x0008)) {
uint8_t colormode = value; device.colormode = val16;
zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
} }
// Iterate on filter // Iterate on filter
@ -1557,11 +1562,6 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) { ((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) {
String new_name_str = (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset)); String new_name_str = (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset));
if (suffix > 1) { new_name_str += suffix; } // append suffix number if (suffix > 1) { new_name_str += suffix; } // append suffix number
// else if (Settings.flag4.zb_index_ep) {
// if (zigbee_devices.countEndpoints(shortaddr) > 0) {
// new_name_str += _srcendpoint;
// }
// }
// apply the transformation // apply the transformation
int32_t drop = Z_ApplyConverter(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute, conv_multiplier, conv_cb); int32_t drop = Z_ApplyConverter(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute, conv_multiplier, conv_cb);
if (drop) { if (drop) {
@ -1572,6 +1572,8 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
} }
} }
} }
updateInternalAttributes(shortaddr, json);
} }
#endif // USE_ZIGBEE #endif // USE_ZIGBEE

View File

@ -1328,46 +1328,61 @@ void ZigbeeShow(bool json)
const uint8_t px_lqi = (strlen(D_LQI) + 4) * 10; // LQI 254 = 70px const uint8_t px_lqi = (strlen(D_LQI) + 4) * 10; // LQI 254 = 70px
WSContentSend_P(PSTR("</table>{t}")); // Terminate current two column table and open new table WSContentSend_P(PSTR("</table>{t}")); // Terminate current two column table and open new table
// WSContentSend_P(PSTR("<tr><td colspan='2'>{t}")); // Insert multi column table
// WSContentSend_PD(PSTR("{s}Device 0x1234</th><td style='width:30%%'>" D_BATT " 100%%</td><td style='width:20%%'>" D_LQI " 254{e}"));
// WSContentSend_PD(PSTR("{s}Device 0x1234</th><td style='width:100px'>" D_BATT " 100%%</td><td style='width:70px'>" D_LQI " 254{e}"));
// WSContentSend_PD(PSTR("{s}Device 0x1234</th><td style='width:%dpx'>" D_BATT " 100%%</td><td style='width:%dpx'>" D_LQI " 254{e}"), px_batt, px_lqi);
char sdevice[33];
char sbatt[20];
char slqi[20];
for (uint32_t i = 0; i < zigbee_num; i++) { for (uint32_t i = 0; i < zigbee_num; i++) {
uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr; const Z_Device &device = zigbee_devices.devicesAt(i);
char *name = (char*)zigbee_devices.getFriendlyName(shortaddr); uint16_t shortaddr = device.shortaddr;
if (nullptr == name) { { // exxplicit scope to free up stack allocated strings
snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr); char *name = (char*) device.friendlyName;
name = sdevice; char sdevice[33];
if (nullptr == name) {
snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr);
name = sdevice;
}
char slqi[8];
snprintf_P(slqi, sizeof(slqi), PSTR("-"));
if (device.validLqi()) {
snprintf_P(slqi, sizeof(slqi), PSTR("%d"), device.lqi);
}
char sbatt[20];
snprintf_P(sbatt, sizeof(sbatt), PSTR("&nbsp;"));
if (device.validBatteryPercent()) {
snprintf_P(sbatt, sizeof(sbatt), PSTR(D_BATT " %d%%"), device.batterypercent);
}
if (!i) { // First row needs style info
WSContentSend_PD(PSTR("<tr><td><b>%s</b></td><td style='width:%dpx'>%s</td><td style='width:%dpx'>" D_LQI " %s{e}"),
name, px_batt, sbatt, px_lqi, slqi);
} else { // Following rows don't need style info so reducing ajax package
WSContentSend_PD(PSTR("<tr><td><b>%s</b></td><td>%s</td><td>" D_LQI " %s{e}"), name, sbatt, slqi);
}
} }
snprintf_P(slqi, sizeof(slqi), PSTR("-")); // Sensor
uint8_t lqi = zigbee_devices.getLQI(shortaddr); bool temperature_ok = device.validTemperature();
if (0xFF != lqi) { bool humidity_ok = device.validHumidity();
snprintf_P(slqi, sizeof(slqi), PSTR("%d"), lqi); bool pressure_ok = device.validPressure();
}
snprintf_P(sbatt, sizeof(sbatt), PSTR("&nbsp;")); if (temperature_ok || humidity_ok || pressure_ok) {
uint8_t bp = zigbee_devices.getBatteryPercent(shortaddr); WSContentSend_P(PSTR("<tr><td colspan=\"3\">| "));
if (0xFF != bp) { if (temperature_ok) {
snprintf_P(sbatt, sizeof(sbatt), PSTR(D_BATT " %d%%"), bp); char buf[12];
} dtostrf(device.temperature / 10.0f, 3, 1, buf);
WSContentSend_PD(PSTR(" &nbsp;&#x2600;&#xFE0F;%s°C"), buf);
if (!i) { // First row needs style info }
WSContentSend_PD(PSTR("{s}%s</th><td style='width:%dpx'>%s</td><td style='width:%dpx'>" D_LQI " %s{e}"), if (humidity_ok) {
name, px_batt, sbatt, px_lqi, slqi); WSContentSend_P(PSTR(" &nbsp;&#x1F4A7;%d%%"), device.humidity);
} else { // Following rows don't need style info so reducing ajax package }
WSContentSend_PD(PSTR("{s}%s{m}%s</td><td>" D_LQI " %s{e}"), name, sbatt, slqi); if (pressure_ok) {
WSContentSend_P(PSTR(" &nbsp;&#x26C5; %d hPa"), device.pressure);
}
WSContentSend_P(PSTR("{e}"));
} }
} }
WSContentSend_P(PSTR("</table>{t}")); // Terminate current multi column table and open new table WSContentSend_P(PSTR("</table>{t}")); // Terminate current multi column table and open new table
// WSContentSend_P(PSTR("</table>{e}")); // Terminate multi column table
#endif #endif
} }
} }