mirror of https://github.com/arendst/Tasmota.git
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:
commit
363b8e6b76
|
@ -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 virtual CT for 4 channels lights, emulating a 5th channel
|
||||
- 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
|
||||
|
||||
|
|
|
@ -1121,8 +1121,6 @@ enum ZCL_Global_Commands {
|
|||
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
|
||||
|
||||
// ZDP Enumeration, see Zigbee spec 2.4.5
|
||||
|
|
|
@ -50,7 +50,9 @@ uint8_t Z_GetLastEndpoint(void) { return gZbLastMessage.endpoint; }
|
|||
|
||||
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
|
||||
char * manufacturerId;
|
||||
char * modelId;
|
||||
|
@ -82,9 +84,69 @@ typedef struct Z_Device {
|
|||
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 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
|
||||
} 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
|
||||
|
@ -136,11 +198,17 @@ public:
|
|||
// - 0x0000 = not found
|
||||
// - BAD_SHORTADDR = bad parameter
|
||||
// - 0x<shortaddr> = the device's short address
|
||||
uint16_t isKnownShortAddr(uint16_t shortaddr) const;
|
||||
uint16_t isKnownLongAddr(uint64_t longaddr) const;
|
||||
uint16_t isKnownIndex(uint32_t index) 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;
|
||||
|
||||
uint8_t findFirstEndpoint(uint16_t shortaddr) const;
|
||||
|
@ -157,12 +225,19 @@ public:
|
|||
void setManufId(uint16_t shortaddr, const char * str);
|
||||
void setModelId(uint16_t shortaddr, const char * str);
|
||||
void setFriendlyName(uint16_t shortaddr, const char * str);
|
||||
const char * getFriendlyName(uint16_t shortaddr) const;
|
||||
const char * getModelId(uint16_t shortaddr) const;
|
||||
const char * getManufacturerId(uint16_t shortaddr) const;
|
||||
inline const char * getFriendlyName(uint16_t shortaddr) const {
|
||||
return findShortAddr(shortaddr).friendlyName;
|
||||
}
|
||||
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 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);
|
||||
uint8_t getBatteryPercent(uint16_t shortaddr) const;
|
||||
|
||||
|
@ -183,18 +258,6 @@ public:
|
|||
int8_t getHueBulbtype(uint16_t shortaddr) const ;
|
||||
void hideHueBulb(uint16_t shortaddr, bool hidden);
|
||||
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
|
||||
void resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category);
|
||||
|
@ -234,20 +297,14 @@ private:
|
|||
uint32_t _saveTimer = 0;
|
||||
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>
|
||||
static bool findInVector(const std::vector<T> & vecOfElements, const T & element);
|
||||
|
||||
template < typename T>
|
||||
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;
|
||||
|
||||
int32_t findShortAddrIdx(uint16_t shortaddr) const;
|
||||
// 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);
|
||||
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
|
||||
// entry with same shortaddr or longaddr exists.
|
||||
//
|
||||
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
|
||||
//Z_Device* device_alloc = (Z_Device*) malloc(sizeof(Z_Device));
|
||||
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
|
||||
};
|
||||
if ((BAD_SHORTADDR == shortaddr) && !longaddr) { return (Z_Device&) device_unk; } // it is not legal to create this entry
|
||||
Z_Device * device_alloc = new Z_Device(shortaddr, longaddr);
|
||||
|
||||
device_alloc->json_buffer = new DynamicJsonBuffer(16);
|
||||
_devices.push_back(device_alloc);
|
||||
|
@ -346,7 +369,7 @@ void Z_Devices::freeDeviceEntry(Z_Device *device) {
|
|||
// Out:
|
||||
// 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)
|
||||
int32_t found = 0;
|
||||
for (auto &elem : _devices) {
|
||||
|
@ -355,6 +378,12 @@ int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const {
|
|||
}
|
||||
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
|
||||
// Looks info device.longaddr entry
|
||||
|
@ -395,16 +424,6 @@ int32_t Z_Devices::findFriendlyName(const char * name) const {
|
|||
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 {
|
||||
int32_t found = findLongAddr(longaddr);
|
||||
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 {
|
||||
const Z_Device &device = getShortAddrConst(shortaddr);
|
||||
return (&device != nullptr) ? device.longaddr : 0;
|
||||
return getShortAddrConst(shortaddr).longaddr; // if unknown, it reverts to the Unknown device and longaddr is 0x00
|
||||
}
|
||||
|
||||
//
|
||||
// We have a seen a shortaddr on the network, get the corresponding device object
|
||||
//
|
||||
Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
||||
if (BAD_SHORTADDR == shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (BAD_SHORTADDR == shortaddr) { return (Z_Device&) device_unk; } // this is not legal
|
||||
int32_t found = findShortAddrIdx(shortaddr);
|
||||
if (found >= 0) {
|
||||
return *(_devices[found]);
|
||||
}
|
||||
|
@ -454,17 +472,16 @@ Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
|||
}
|
||||
// Same version but 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 = findShortAddr(shortaddr);
|
||||
int32_t found = findShortAddrIdx(shortaddr);
|
||||
if (found >= 0) {
|
||||
return *(_devices[found]);
|
||||
}
|
||||
return *((Z_Device*)nullptr);
|
||||
return device_unk;
|
||||
}
|
||||
|
||||
// find the Device object by its longaddr (unique key if not null)
|
||||
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);
|
||||
if (found > 0) {
|
||||
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
|
||||
bool Z_Devices::removeDevice(uint16_t shortaddr) {
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
int32_t found = findShortAddrIdx(shortaddr);
|
||||
if (found >= 0) {
|
||||
freeDeviceEntry(_devices.at(found));
|
||||
_devices.erase(_devices.begin() + found);
|
||||
|
@ -490,7 +507,7 @@ bool Z_Devices::removeDevice(uint16_t shortaddr) {
|
|||
// shortaddr
|
||||
// longaddr (both can't be null at the same time)
|
||||
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
|
||||
|
||||
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) {
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
device.endpoints[i] = 0;
|
||||
// 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) {
|
||||
if (0x00 == endpoint) { return; }
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
for (uint32_t i = 0; i < endpoints_max; 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 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
|
||||
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 {
|
||||
// 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; }
|
||||
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
|
||||
return findShortAddr(shortaddr).endpoints[0]; // returns 0x00 if no endpoint
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
setStringAttribute(device.manufacturerId, str);
|
||||
setStringAttribute(getShortAddr(shortaddr).manufacturerId, str);
|
||||
}
|
||||
|
||||
void Z_Devices::setModelId(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
setStringAttribute(device.modelId, str);
|
||||
setStringAttribute(getShortAddr(shortaddr).modelId, str);
|
||||
}
|
||||
|
||||
void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
setStringAttribute(device.friendlyName, str);
|
||||
setStringAttribute(getShortAddr(shortaddr).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) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
bitWrite(device.power, 7, reachable);
|
||||
getShortAddr(shortaddr).setReachable(reachable);
|
||||
}
|
||||
|
||||
void Z_Devices::setLQI(uint16_t shortaddr, uint8_t lqi) {
|
||||
if (shortaddr == localShortAddr) { return; }
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
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;
|
||||
getShortAddr(shortaddr).lqi = lqi;
|
||||
}
|
||||
|
||||
void Z_Devices::setBatteryPercent(uint16_t shortaddr, uint8_t bp) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
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;
|
||||
getShortAddr(shortaddr).batterypercent = bp;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
int32_t short_found = findShortAddr(shortaddr);
|
||||
int32_t short_found = findShortAddrIdx(shortaddr);
|
||||
if (short_found >= 0) {
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
device.seqNumber += 1;
|
||||
|
@ -732,7 +682,7 @@ void Z_Devices::updateZbProfile(uint16_t shortaddr) {
|
|||
{
|
||||
uint32_t channels = zb_profile & 0x07;
|
||||
// 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 (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
|
||||
uint8_t Z_Devices::getZbProfile(uint16_t shortaddr) const {
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (found >= 0) {
|
||||
return _devices[found]->zb_profile;
|
||||
} else {
|
||||
return 0xFF; // Hue not activated
|
||||
}
|
||||
return findShortAddr(shortaddr).zb_profile;
|
||||
}
|
||||
|
||||
// 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
|
||||
bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const {
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
int32_t found = findShortAddrIdx(shortaddr);
|
||||
if (found >= 0) {
|
||||
uint8_t zb_profile = _devices[found]->zb_profile;
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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) {
|
||||
|
@ -907,8 +808,6 @@ void Z_Devices::runTimer(void) {
|
|||
// Clear the JSON buffer for coalesced and deferred attributes
|
||||
void Z_Devices::jsonClear(uint16_t shortaddr) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
device.json = nullptr;
|
||||
device.json_buffer->clear();
|
||||
}
|
||||
|
@ -961,7 +860,6 @@ void CopyJsonObject(JsonObject &to, const JsonObject &from) {
|
|||
// false - new attributes can be safely added
|
||||
bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return false; } // don't crash if not found
|
||||
if (&values == nullptr) { return false; }
|
||||
|
||||
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) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
if (&values == nullptr) { return; }
|
||||
|
||||
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) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return nullptr; } // don't crash if not found
|
||||
return device.json;
|
||||
return getShortAddr(shortaddr).json;
|
||||
}
|
||||
|
||||
void Z_Devices::jsonPublishFlush(uint16_t 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;
|
||||
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);
|
||||
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
|
||||
shortaddr = strtoull(dataBuf, nullptr, 0);
|
||||
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 {
|
||||
|
@ -1133,7 +1028,7 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
|
|||
JsonObject& json = jsonBuffer.createObject();
|
||||
char hex[8];
|
||||
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
int32_t found = findShortAddrIdx(shortaddr);
|
||||
if (found >= 0) {
|
||||
const Z_Device & device = devicesAt(found);
|
||||
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
|
||||
dev[F(D_JSON_ZIGBEE_LIGHT)] = getHueBulbtype(shortaddr); // sign extend, 0xFF changed as -1
|
||||
// dump all known values
|
||||
dev[F("Reachable")] = bitRead(device.power, 7); // TODO TODO
|
||||
if (0xFF != device.power) { dev[F("Power")] = bitRead(device.power, 0); }
|
||||
if (0xFF != device.dimmer) { dev[F("Dimmer")] = device.dimmer; }
|
||||
if (0xFF != device.colormode) { dev[F("Colormode")] = device.colormode; }
|
||||
if (0xFFFF != device.ct) { dev[F("CT")] = device.ct; }
|
||||
if (0xFF != device.sat) { dev[F("Sat")] = device.sat; }
|
||||
if (0xFFFF != device.hue) { dev[F("Hue")] = device.hue; }
|
||||
if (0xFFFF != device.x) { dev[F("X")] = device.x; }
|
||||
if (0xFFFF != device.y) { dev[F("Y")] = device.y; }
|
||||
dev[F("Reachable")] = device.getReachable(); // TODO TODO
|
||||
if (device.validPower()) { dev[F("Power")] = device.getPower(); }
|
||||
if (device.validDimmer()) { dev[F("Dimmer")] = device.dimmer; }
|
||||
if (device.validColormode()) { dev[F("Colormode")] = device.colormode; }
|
||||
if (device.validCT()) { dev[F("CT")] = device.ct; }
|
||||
if (device.validSat()) { dev[F("Sat")] = device.sat; }
|
||||
if (device.validHue()) { dev[F("Hue")] = device.hue; }
|
||||
if (device.validX()) { dev[F("X")] = device.x; }
|
||||
if (device.validY()) { dev[F("Y")] = device.y; }
|
||||
}
|
||||
|
||||
String payload = "";
|
||||
|
|
|
@ -36,7 +36,17 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
|
|||
String light_status = "";
|
||||
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 < 1) bri = 1;
|
||||
|
@ -78,9 +88,10 @@ void HueLightStatus2Zigbee(uint16_t shortaddr, String *response)
|
|||
const size_t buf_size = 300;
|
||||
char * buf = (char*) malloc(buf_size);
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
|
||||
const char * modelId = zigbee_devices.getModelId(shortaddr);
|
||||
const char * manufacturerId = zigbee_devices.getManufacturerId(shortaddr);
|
||||
const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
|
||||
const char * friendlyName = device.friendlyName;
|
||||
const char * modelId = device.modelId;
|
||||
const char * manufacturerId = device.manufacturerId;
|
||||
char shortaddrname[8];
|
||||
snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr);
|
||||
|
||||
|
@ -137,7 +148,7 @@ void ZigbeeHueGroups(String * lights) {
|
|||
// Power On/Off
|
||||
void ZigbeeHuePower(uint16_t shortaddr, bool power) {
|
||||
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
|
||||
|
@ -146,7 +157,7 @@ void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) {
|
|||
char param[8];
|
||||
snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer);
|
||||
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
|
||||
|
@ -157,7 +168,9 @@ void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) {
|
|||
snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8);
|
||||
uint8_t colormode = 2; // "ct"
|
||||
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
|
||||
|
@ -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);
|
||||
uint8_t colormode = 1; // "xy"
|
||||
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
|
||||
|
@ -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);
|
||||
uint8_t colormode = 0; // "hs"
|
||||
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) {
|
||||
|
|
|
@ -445,7 +445,7 @@ const char Z_strings[] PROGMEM =
|
|||
"AddScene" "\x00"
|
||||
"xxyyyyzz" "\x00"
|
||||
"StoreScene" "\x00"
|
||||
"\x00";
|
||||
;
|
||||
|
||||
|
||||
enum Z_offsets {
|
||||
|
|
|
@ -626,6 +626,7 @@ public:
|
|||
void parseResponse(void);
|
||||
void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0);
|
||||
void postProcessAttributes(uint16_t shortaddr, JsonObject& json);
|
||||
void updateInternalAttributes(uint16_t shortaddr, JsonObject& json);
|
||||
|
||||
inline void setGroupId(uint16_t groupid) {
|
||||
_groupaddr = groupid;
|
||||
|
@ -1224,7 +1225,7 @@ int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu
|
|||
|
||||
// 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) {
|
||||
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);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// source endpoint
|
||||
uint8_t src_ep = _srcendpoint;
|
||||
|
@ -1509,40 +1528,26 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
|||
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
|
||||
if ((cluster == 0x0006) && ((attribute == 0x0000) || (attribute == 0x8000))) {
|
||||
bool power = value;
|
||||
zigbee_devices.updateHueState(shortaddr, &power, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
device.setPower(power);
|
||||
} else if ((cluster == 0x0008) && (attribute == 0x0000)) {
|
||||
uint8_t dimmer = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, &dimmer, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
device.dimmer = val16;
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0000)) {
|
||||
uint16_t hue8 = value;
|
||||
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);
|
||||
device.hue = changeUIntScale(val16, 0, 254, 0, 360); // change range from 0..254 to 0..360
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0001)) {
|
||||
uint8_t sat = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, &sat,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
device.sat = val16;
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0003)) {
|
||||
uint16_t x = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &x, nullptr, nullptr);
|
||||
device.x = val16;
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0004)) {
|
||||
uint16_t y = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, &y, nullptr), nullptr;
|
||||
device.y = val16;
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0007)) {
|
||||
uint16_t ct = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr,
|
||||
&ct, nullptr, nullptr, nullptr, nullptr);
|
||||
device.ct = val16;
|
||||
} else if ((cluster == 0x0300) && (attribute == 0x0008)) {
|
||||
uint8_t colormode = value;
|
||||
zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
device.colormode = val16;
|
||||
}
|
||||
|
||||
// Iterate on filter
|
||||
|
@ -1557,11 +1562,6 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
|||
((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) {
|
||||
String new_name_str = (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset));
|
||||
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
|
||||
int32_t drop = Z_ApplyConverter(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute, conv_multiplier, conv_cb);
|
||||
if (drop) {
|
||||
|
@ -1572,6 +1572,8 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateInternalAttributes(shortaddr, json);
|
||||
}
|
||||
|
||||
#endif // USE_ZIGBEE
|
||||
|
|
|
@ -1328,46 +1328,61 @@ void ZigbeeShow(bool json)
|
|||
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("<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++) {
|
||||
uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
|
||||
char *name = (char*)zigbee_devices.getFriendlyName(shortaddr);
|
||||
if (nullptr == name) {
|
||||
snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr);
|
||||
name = sdevice;
|
||||
const Z_Device &device = zigbee_devices.devicesAt(i);
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
{ // exxplicit scope to free up stack allocated strings
|
||||
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 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(" "));
|
||||
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("-"));
|
||||
uint8_t lqi = zigbee_devices.getLQI(shortaddr);
|
||||
if (0xFF != lqi) {
|
||||
snprintf_P(slqi, sizeof(slqi), PSTR("%d"), lqi);
|
||||
}
|
||||
// Sensor
|
||||
bool temperature_ok = device.validTemperature();
|
||||
bool humidity_ok = device.validHumidity();
|
||||
bool pressure_ok = device.validPressure();
|
||||
|
||||
snprintf_P(sbatt, sizeof(sbatt), PSTR(" "));
|
||||
uint8_t bp = zigbee_devices.getBatteryPercent(shortaddr);
|
||||
if (0xFF != bp) {
|
||||
snprintf_P(sbatt, sizeof(sbatt), PSTR(D_BATT " %d%%"), bp);
|
||||
}
|
||||
|
||||
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}"),
|
||||
name, px_batt, sbatt, px_lqi, slqi);
|
||||
} 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 (temperature_ok || humidity_ok || pressure_ok) {
|
||||
WSContentSend_P(PSTR("<tr><td colspan=\"3\">| "));
|
||||
if (temperature_ok) {
|
||||
char buf[12];
|
||||
dtostrf(device.temperature / 10.0f, 3, 1, buf);
|
||||
WSContentSend_PD(PSTR(" ☀️%s°C"), buf);
|
||||
}
|
||||
if (humidity_ok) {
|
||||
WSContentSend_P(PSTR(" 💧%d%%"), device.humidity);
|
||||
}
|
||||
if (pressure_ok) {
|
||||
WSContentSend_P(PSTR(" ⛅ %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>{e}")); // Terminate multi column table
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue