mirror of https://github.com/arendst/Tasmota.git
Merge pull request #9701 from s-hadinger/zigbee_nov_1
Zigbee refactoring
This commit is contained in:
commit
1d5b74e3ec
|
@ -543,6 +543,9 @@ public:
|
|||
inline bool getReachable(void) const { return reachable; }
|
||||
inline bool getPower(uint8_t ep =0) const;
|
||||
|
||||
inline void setLQI(uint8_t _lqi) { lqi = _lqi; }
|
||||
inline void setBatteryPercent(uint8_t bp) { batterypercent = bp; }
|
||||
|
||||
// Add an endpoint to a device
|
||||
bool addEndpoint(uint8_t endpoint);
|
||||
void clearEndpoints(void);
|
||||
|
@ -552,6 +555,8 @@ public:
|
|||
void setModelId(const char * str);
|
||||
void setFriendlyName(const char * str);
|
||||
|
||||
void setLastSeenNow(void);
|
||||
|
||||
// dump device attributes to ZbData
|
||||
void toAttributes(Z_attribute_list & attr_list) const;
|
||||
|
||||
|
@ -568,30 +573,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// returns: dirty flag, did we change the value of the object
|
||||
bool setLightChannels(int8_t channels) {
|
||||
bool dirty = false;
|
||||
if (channels >= 0) {
|
||||
// retrieve of create light object
|
||||
Z_Data_Light & light = data.get<Z_Data_Light>(0);
|
||||
if (channels != light.getConfig()) {
|
||||
light.setConfig(channels);
|
||||
dirty = true;
|
||||
}
|
||||
Z_Data_OnOff & onoff = data.get<Z_Data_OnOff>(0);
|
||||
} else {
|
||||
// remove light / onoff object if any
|
||||
for (auto & data_elt : data) {
|
||||
if ((data_elt.getType() == Z_Data_Type::Z_Light) ||
|
||||
(data_elt.getType() == Z_Data_Type::Z_OnOff)) {
|
||||
// remove light object
|
||||
data.remove(&data_elt);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dirty;
|
||||
}
|
||||
void setLightChannels(int8_t channels);
|
||||
|
||||
protected:
|
||||
|
||||
static void setStringAttribute(char*& attr, const char * str);
|
||||
|
@ -655,9 +638,9 @@ public:
|
|||
// - 0x0000 = not found
|
||||
// - BAD_SHORTADDR = bad parameter
|
||||
// - 0x<shortaddr> = the device's short address
|
||||
uint16_t isKnownLongAddr(uint64_t longaddr) const;
|
||||
uint16_t isKnownIndex(uint32_t index) const;
|
||||
uint16_t isKnownFriendlyName(const char * name) const;
|
||||
Z_Device & isKnownLongAddrDevice(uint64_t longaddr) const;
|
||||
Z_Device & isKnownIndexDevice(uint32_t index) const;
|
||||
Z_Device & isKnownFriendlyNameDevice(const char * name) const;
|
||||
|
||||
Z_Device & findShortAddr(uint16_t shortaddr);
|
||||
const Z_Device & findShortAddr(uint16_t shortaddr) const;
|
||||
|
@ -666,9 +649,7 @@ public:
|
|||
Z_Device & getShortAddr(uint16_t shortaddr); // 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
|
||||
// check if a device was found or if it's the fallback device
|
||||
inline bool foundDevice(const Z_Device & device) const {
|
||||
return (&device != &device_unk);
|
||||
}
|
||||
inline bool foundDevice(const Z_Device & device) const { return device.valid(); }
|
||||
|
||||
int32_t findFriendlyName(const char * name) const;
|
||||
uint64_t getDeviceLongAddr(uint16_t shortaddr) const;
|
||||
|
@ -689,26 +670,15 @@ public:
|
|||
return findShortAddr(shortaddr).manufacturerId;
|
||||
}
|
||||
|
||||
void setReachable(uint16_t shortaddr, bool reachable);
|
||||
void setLQI(uint16_t shortaddr, uint8_t lqi);
|
||||
void setLastSeenNow(uint16_t shortaddr);
|
||||
// uint8_t getLQI(uint16_t shortaddr) const;
|
||||
void setBatteryPercent(uint16_t shortaddr, uint8_t bp);
|
||||
uint8_t getBatteryPercent(uint16_t shortaddr) const;
|
||||
|
||||
// get next sequence number for (increment at each all)
|
||||
uint8_t getNextSeqNumber(uint16_t shortaddr);
|
||||
|
||||
// Dump json
|
||||
static void addLightState(Z_attribute_list & attr_list, const Z_Data_Light & light);
|
||||
String dumpLightState(uint16_t shortaddr) const;
|
||||
String dump(uint32_t dump_mode, uint16_t status_shortaddr = 0) const;
|
||||
String dumpDevice(uint32_t dump_mode, const Z_Device & device) const;
|
||||
static String dumpSingleDevice(uint32_t dump_mode, const Z_Device & device);
|
||||
int32_t deviceRestore(JsonParserObject json);
|
||||
|
||||
// General Zigbee device profile support
|
||||
void setLightProfile(uint16_t shortaddr, uint8_t light_profile);
|
||||
uint8_t getLightProfile(uint16_t shortaddr) const ;
|
||||
|
||||
// Hue support
|
||||
int8_t getHueBulbtype(uint16_t shortaddr) const ;
|
||||
void hideHueBulb(uint16_t shortaddr, bool hidden);
|
||||
|
@ -731,14 +701,7 @@ public:
|
|||
size_t devicesSize(void) const {
|
||||
return _devices.length();
|
||||
}
|
||||
const Z_Device & devicesAt(size_t i) const {
|
||||
const Z_Device * devp = _devices.at(i);
|
||||
if (devp) {
|
||||
return *devp;
|
||||
} else {
|
||||
return device_unk;
|
||||
}
|
||||
}
|
||||
Z_Device & devicesAt(size_t i) const;
|
||||
|
||||
// Remove device from list
|
||||
bool removeDevice(uint16_t shortaddr);
|
||||
|
@ -746,10 +709,10 @@ public:
|
|||
// Mark data as 'dirty' and requiring to save in Flash
|
||||
void dirty(void);
|
||||
void clean(void); // avoid writing to flash the last changes
|
||||
void shrinkToFit(uint16_t shortaddr);
|
||||
|
||||
// Find device by name, can be short_addr, long_addr, number_in_array or name
|
||||
uint16_t parseDeviceParam(const char * param, bool short_must_be_known = false) const;
|
||||
Z_Device & parseDeviceFromName(const char * param, bool short_must_be_known = false);
|
||||
|
||||
|
||||
private:
|
||||
LList<Z_Device> _devices; // list of devices
|
||||
|
@ -757,10 +720,6 @@ 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);
|
||||
|
||||
//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);
|
||||
|
@ -772,6 +731,10 @@ private:
|
|||
\*********************************************************************************************/
|
||||
Z_Devices zigbee_devices = Z_Devices();
|
||||
|
||||
// Following device is used represent the unknown device, with all defaults
|
||||
// Any find() function will not return Null, instead it will return this instance
|
||||
Z_Device device_unk = Z_Device(BAD_SHORTADDR);
|
||||
|
||||
// Local coordinator information
|
||||
uint64_t localIEEEAddr = 0;
|
||||
uint16_t localShortAddr = 0;
|
||||
|
|
|
@ -23,12 +23,21 @@
|
|||
* Implementation
|
||||
\*********************************************************************************************/
|
||||
|
||||
Z_Device & Z_Devices::devicesAt(size_t i) const {
|
||||
Z_Device * devp = (Z_Device*) _devices.at(i);
|
||||
if (devp) {
|
||||
return *devp;
|
||||
} else {
|
||||
return device_unk;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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&) device_unk; } // it is not legal to create this entry
|
||||
if ((BAD_SHORTADDR == shortaddr) && !longaddr) { return device_unk; } // it is not legal to create this entry
|
||||
Z_Device & device = _devices.addToLast();
|
||||
device.shortaddr = shortaddr;
|
||||
device.longaddr = longaddr;
|
||||
|
@ -56,7 +65,7 @@ Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) {
|
|||
for (auto & elem : _devices) {
|
||||
if (elem.shortaddr == shortaddr) { return elem; }
|
||||
}
|
||||
return (Z_Device&) device_unk;
|
||||
return device_unk;
|
||||
}
|
||||
const Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) const {
|
||||
for (const auto & elem : _devices) {
|
||||
|
@ -73,11 +82,11 @@ const Z_Device & Z_Devices::findShortAddr(uint16_t shortaddr) const {
|
|||
// index in _devices of entry, -1 if not found
|
||||
//
|
||||
Z_Device & Z_Devices::findLongAddr(uint64_t longaddr) {
|
||||
if (!longaddr) { return (Z_Device&) device_unk; }
|
||||
if (!longaddr) { return device_unk; }
|
||||
for (auto &elem : _devices) {
|
||||
if (elem.longaddr == longaddr) { return elem; }
|
||||
}
|
||||
return (Z_Device&) device_unk;
|
||||
return device_unk;
|
||||
}
|
||||
const Z_Device & Z_Devices::findLongAddr(uint64_t longaddr) const {
|
||||
if (!longaddr) { return device_unk; }
|
||||
|
@ -109,32 +118,25 @@ int32_t Z_Devices::findFriendlyName(const char * name) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const {
|
||||
const Z_Device & device = findLongAddr(longaddr);
|
||||
if (foundDevice(device)) {
|
||||
return device.shortaddr; // can be zero, if not yet registered
|
||||
} else {
|
||||
return BAD_SHORTADDR;
|
||||
}
|
||||
Z_Device & Z_Devices::isKnownLongAddrDevice(uint64_t longaddr) const {
|
||||
return (Z_Device &) findLongAddr(longaddr);
|
||||
}
|
||||
|
||||
uint16_t Z_Devices::isKnownIndex(uint32_t index) const {
|
||||
Z_Device & Z_Devices::isKnownIndexDevice(uint32_t index) const {
|
||||
if (index < devicesSize()) {
|
||||
const Z_Device & device = devicesAt(index);
|
||||
return device.shortaddr;
|
||||
return devicesAt(index);
|
||||
} else {
|
||||
return BAD_SHORTADDR;
|
||||
return device_unk;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Z_Devices::isKnownFriendlyName(const char * name) const {
|
||||
if ((!name) || (0 == strlen(name))) { return BAD_SHORTADDR; } // Error
|
||||
Z_Device & Z_Devices::isKnownFriendlyNameDevice(const char * name) const {
|
||||
if ((!name) || (0 == strlen(name))) { return device_unk; } // Error
|
||||
int32_t found = findFriendlyName(name);
|
||||
if (found >= 0) {
|
||||
const Z_Device & device = devicesAt(found);
|
||||
return device.shortaddr; // can be zero, if not yet registered
|
||||
return devicesAt(found);
|
||||
} else {
|
||||
return BAD_SHORTADDR;
|
||||
return device_unk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +148,7 @@ uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const {
|
|||
// 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&) device_unk; } // this is not legal
|
||||
if (BAD_SHORTADDR == shortaddr) { return device_unk; } // this is not legal
|
||||
Z_Device & device = findShortAddr(shortaddr);
|
||||
if (foundDevice(device)) {
|
||||
return device;
|
||||
|
@ -156,7 +158,7 @@ Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
|||
|
||||
// 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&) device_unk; }
|
||||
if (!longaddr) { return device_unk; }
|
||||
Z_Device & device = findLongAddr(longaddr);
|
||||
if (foundDevice(device)) {
|
||||
return device;
|
||||
|
@ -211,7 +213,7 @@ Z_Device & Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
|
|||
if ((BAD_SHORTADDR != shortaddr) || longaddr) {
|
||||
return createDeviceEntry(shortaddr, longaddr);
|
||||
}
|
||||
return (Z_Device&) device_unk;
|
||||
return device_unk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,29 +310,13 @@ void Z_Device::setFriendlyName(const char * str) {
|
|||
setStringAttribute(friendlyName, str);
|
||||
}
|
||||
|
||||
|
||||
void Z_Devices::setReachable(uint16_t shortaddr, bool reachable) {
|
||||
getShortAddr(shortaddr).setReachable(reachable);
|
||||
}
|
||||
|
||||
void Z_Devices::setLQI(uint16_t shortaddr, uint8_t lqi) {
|
||||
if (shortaddr == localShortAddr) { return; }
|
||||
getShortAddr(shortaddr).lqi = lqi;
|
||||
}
|
||||
|
||||
void Z_Devices::setLastSeenNow(uint16_t shortaddr) {
|
||||
if (shortaddr == localShortAddr) { return; }
|
||||
void Z_Device::setLastSeenNow(void) {
|
||||
// Only update time if after 2020-01-01 0000.
|
||||
// Fixes issue where zigbee device pings before WiFi/NTP has set utc_time
|
||||
// to the correct time, and "last seen" calculations are based on the
|
||||
// pre-corrected last_seen time and the since-corrected utc_time.
|
||||
if (Rtc.utc_time < 1577836800) { return; }
|
||||
getShortAddr(shortaddr).last_seen = Rtc.utc_time;
|
||||
}
|
||||
|
||||
|
||||
void Z_Devices::setBatteryPercent(uint16_t shortaddr, uint8_t bp) {
|
||||
getShortAddr(shortaddr).batterypercent = bp;
|
||||
last_seen = Rtc.utc_time;
|
||||
}
|
||||
|
||||
// get the next sequance number for the device, or use the global seq number if device is unknown
|
||||
|
@ -345,22 +331,32 @@ uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) {
|
|||
}
|
||||
}
|
||||
|
||||
// General Zigbee device profile support
|
||||
void Z_Devices::setLightProfile(uint16_t shortaddr, uint8_t light_profile) {
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (device.setLightChannels(light_profile)) {
|
||||
dirty();
|
||||
// returns: dirty flag, did we change the value of the object
|
||||
void Z_Device::setLightChannels(int8_t channels) {
|
||||
if (channels >= 0) {
|
||||
// retrieve of create light object
|
||||
Z_Data_Light & light = data.get<Z_Data_Light>(0);
|
||||
if (channels != light.getConfig()) {
|
||||
light.setConfig(channels);
|
||||
zigbee_devices.dirty();
|
||||
}
|
||||
Z_Data_OnOff & onoff = data.get<Z_Data_OnOff>(0);
|
||||
} else {
|
||||
// remove light / onoff object if any
|
||||
for (auto & data_elt : data) {
|
||||
if ((data_elt.getType() == Z_Data_Type::Z_Light) ||
|
||||
(data_elt.getType() == Z_Data_Type::Z_OnOff)) {
|
||||
// remove light object
|
||||
data.remove(&data_elt);
|
||||
zigbee_devices.dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the device profile or 0xFF if the device or profile is unknown
|
||||
uint8_t Z_Devices::getLightProfile(uint16_t shortaddr) const {
|
||||
const Z_Device &device = findShortAddr(shortaddr);
|
||||
return device.getLightChannels();
|
||||
}
|
||||
|
||||
int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr) const {
|
||||
int8_t light_profile = getLightProfile(shortaddr);
|
||||
const Z_Device &device = findShortAddr(shortaddr);
|
||||
int8_t light_profile = device.getLightChannels();
|
||||
if (0x00 == (light_profile & 0xF0)) {
|
||||
return (light_profile & 0x07);
|
||||
} else {
|
||||
|
@ -575,39 +571,39 @@ void Z_Devices::clean(void) {
|
|||
// - a long address starting with "0x", example: 0x7CB03EBB0A0292DD
|
||||
// - a number 0..99, the index number in ZigbeeStatus
|
||||
// - a friendly name, between quotes, example: "Room_Temp"
|
||||
uint16_t Z_Devices::parseDeviceParam(const char * param, bool short_must_be_known) const {
|
||||
if (nullptr == param) { return BAD_SHORTADDR; }
|
||||
Z_Device & Z_Devices::parseDeviceFromName(const char * param, bool short_must_be_known) {
|
||||
if (nullptr == param) { return device_unk; }
|
||||
size_t param_len = strlen(param);
|
||||
char dataBuf[param_len + 1];
|
||||
strcpy(dataBuf, param);
|
||||
RemoveSpace(dataBuf);
|
||||
uint16_t shortaddr = BAD_SHORTADDR; // start with unknown
|
||||
|
||||
if (strlen(dataBuf) < 4) {
|
||||
if ((dataBuf[0] >= '0') && (dataBuf[0] <= '9') && (strlen(dataBuf) < 4)) {
|
||||
// simple number 0..99
|
||||
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 99)) {
|
||||
shortaddr = zigbee_devices.isKnownIndex(XdrvMailbox.payload - 1);
|
||||
return isKnownIndexDevice(XdrvMailbox.payload - 1);
|
||||
} else {
|
||||
return device_unk;
|
||||
}
|
||||
} else if ((dataBuf[0] == '0') && ((dataBuf[1] == 'x') || (dataBuf[1] == 'X'))) {
|
||||
// starts with 0x
|
||||
if (strlen(dataBuf) < 18) {
|
||||
// expect a short address
|
||||
shortaddr = strtoull(dataBuf, nullptr, 0);
|
||||
uint16_t shortaddr = strtoull(dataBuf, nullptr, 0);
|
||||
if (short_must_be_known) {
|
||||
shortaddr = zigbee_devices.findShortAddr(shortaddr).shortaddr; // if not found, it reverts to the unknown_device with address BAD_SHORTADDR
|
||||
return (Z_Device&) findShortAddr(shortaddr); // if not found, it reverts to the unknown_device with address BAD_SHORTADDR
|
||||
} else {
|
||||
return getShortAddr(shortaddr); // create it if not registered
|
||||
}
|
||||
// else we don't check if it's already registered to force unregistered devices
|
||||
} else {
|
||||
// expect a long address
|
||||
uint64_t longaddr = strtoull(dataBuf, nullptr, 0);
|
||||
shortaddr = zigbee_devices.isKnownLongAddr(longaddr);
|
||||
return isKnownLongAddrDevice(longaddr);
|
||||
}
|
||||
} else {
|
||||
// expect a Friendly Name
|
||||
shortaddr = zigbee_devices.isKnownFriendlyName(dataBuf);
|
||||
return isKnownFriendlyNameDevice(dataBuf);
|
||||
}
|
||||
|
||||
return shortaddr;
|
||||
}
|
||||
|
||||
// Display the tracked status for a light
|
||||
|
@ -654,60 +650,70 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
|
|||
// Dump the internal memory of Zigbee devices
|
||||
// Mode = 1: simple dump of devices addresses
|
||||
// Mode = 2: simple dump of devices addresses and names, endpoints, light
|
||||
String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const {
|
||||
String Z_Devices::dumpSingleDevice(uint32_t dump_mode, const class Z_Device & device) {
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
char hex[22];
|
||||
|
||||
Z_attribute_list attr_list;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
|
||||
attr_list.addAttribute(F(D_JSON_ZIGBEE_DEVICE)).setStr(hex);
|
||||
|
||||
if (device.friendlyName > 0) {
|
||||
attr_list.addAttribute(F(D_JSON_ZIGBEE_NAME)).setStr(device.friendlyName);
|
||||
}
|
||||
|
||||
if (2 <= dump_mode) {
|
||||
hex[0] = '0'; // prefix with '0x'
|
||||
hex[1] = 'x';
|
||||
Uint64toHex(device.longaddr, &hex[2], 64);
|
||||
attr_list.addAttribute(F("IEEEAddr")).setStr(hex);
|
||||
if (device.modelId) {
|
||||
attr_list.addAttribute(F(D_JSON_MODEL D_JSON_ID)).setStr(device.modelId);
|
||||
}
|
||||
if (device.manufacturerId) {
|
||||
attr_list.addAttribute(F("Manufacturer")).setStr(device.manufacturerId);
|
||||
}
|
||||
|
||||
JsonGeneratorArray arr_ep;
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
uint8_t endpoint = device.endpoints[i];
|
||||
if (0x00 == endpoint) { break; }
|
||||
arr_ep.add(endpoint);
|
||||
}
|
||||
attr_list.addAttribute(F("Endpoints")).setStrRaw(arr_ep.toString().c_str());
|
||||
|
||||
JsonGeneratorArray arr_data;
|
||||
for (auto & data_elt : device.data) {
|
||||
char key[8];
|
||||
if (data_elt.validConfig()) {
|
||||
snprintf_P(key, sizeof(key), "?%02X.%1X", data_elt.getEndpoint(), data_elt.getConfig());
|
||||
} else {
|
||||
snprintf_P(key, sizeof(key), "?%02X", data_elt.getEndpoint());
|
||||
}
|
||||
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
|
||||
arr_data.addStr(key);
|
||||
}
|
||||
attr_list.addAttribute(F("Config")).setStrRaw(arr_data.toString().c_str());
|
||||
}
|
||||
return attr_list.toString(true);
|
||||
}
|
||||
|
||||
// If &device == nullptr, then dump all
|
||||
String Z_Devices::dumpDevice(uint32_t dump_mode, const Z_Device & device) const {
|
||||
JsonGeneratorArray json_arr;
|
||||
|
||||
for (const auto & device : _devices) {
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
char hex[22];
|
||||
|
||||
// ignore non-current device, if device specified
|
||||
if ((BAD_SHORTADDR != status_shortaddr) && (status_shortaddr != shortaddr)) { continue; }
|
||||
|
||||
Z_attribute_list attr_list;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
|
||||
attr_list.addAttribute(F(D_JSON_ZIGBEE_DEVICE)).setStr(hex);
|
||||
|
||||
if (device.friendlyName > 0) {
|
||||
attr_list.addAttribute(F(D_JSON_ZIGBEE_NAME)).setStr(device.friendlyName);
|
||||
if (&device == nullptr) {
|
||||
if (dump_mode < 2) {
|
||||
// dump light mode for all devices
|
||||
for (const auto & device2 : _devices) {
|
||||
json_arr.addStrRaw(dumpSingleDevice(dump_mode, device2).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (2 <= dump_mode) {
|
||||
hex[0] = '0'; // prefix with '0x'
|
||||
hex[1] = 'x';
|
||||
Uint64toHex(device.longaddr, &hex[2], 64);
|
||||
attr_list.addAttribute(F("IEEEAddr")).setStr(hex);
|
||||
if (device.modelId) {
|
||||
attr_list.addAttribute(F(D_JSON_MODEL D_JSON_ID)).setStr(device.modelId);
|
||||
}
|
||||
if (device.manufacturerId) {
|
||||
attr_list.addAttribute(F("Manufacturer")).setStr(device.manufacturerId);
|
||||
}
|
||||
|
||||
JsonGeneratorArray arr_ep;
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
uint8_t endpoint = device.endpoints[i];
|
||||
if (0x00 == endpoint) { break; }
|
||||
arr_ep.add(endpoint);
|
||||
}
|
||||
attr_list.addAttribute(F("Endpoints")).setStrRaw(arr_ep.toString().c_str());
|
||||
|
||||
JsonGeneratorArray arr_data;
|
||||
for (auto & data_elt : device.data) {
|
||||
char key[8];
|
||||
if (data_elt.validConfig()) {
|
||||
snprintf_P(key, sizeof(key), "?%02X.%1X", data_elt.getEndpoint(), data_elt.getConfig());
|
||||
} else {
|
||||
snprintf_P(key, sizeof(key), "?%02X", data_elt.getEndpoint());
|
||||
}
|
||||
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
|
||||
arr_data.addStr(key);
|
||||
}
|
||||
attr_list.addAttribute(F("Config")).setStrRaw(arr_data.toString().c_str());
|
||||
}
|
||||
json_arr.addStrRaw(attr_list.toString(true).c_str());
|
||||
} else {
|
||||
json_arr.addStrRaw(dumpSingleDevice(dump_mode, device).c_str());
|
||||
}
|
||||
|
||||
return json_arr.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -257,7 +257,7 @@ void hydrateSingleDevice(const SBuffer & buf_d, uint32_t version) {
|
|||
|
||||
// Hue bulbtype - if present
|
||||
if (1 == version) {
|
||||
zigbee_devices.setLightProfile(shortaddr, buf_d.get8(d));
|
||||
device.setLightChannels(buf_d.get8(d));
|
||||
d++;
|
||||
} else if (2 == version) {
|
||||
// v2 parser
|
||||
|
|
|
@ -1853,7 +1853,7 @@ void Z_postProcessAttributes(uint16_t shortaddr, uint16_t src_ep, class Z_attrib
|
|||
switch (ccccaaaa) {
|
||||
case 0x00000004: device.setManufId(attr.getStr()); break;
|
||||
case 0x00000005: device.setModelId(attr.getStr()); break;
|
||||
case 0x00010021: zigbee_devices.setBatteryPercent(shortaddr, uval16 / 2); break;
|
||||
case 0x00010021: device.setBatteryPercent(uval16 / 2); break;
|
||||
case 0x00060000:
|
||||
case 0x00068000: device.setPower(attr.getBool(), src_ep); break;
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ void Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster
|
|||
// This callback is registered after a an attribute read command was made to a light, and fires if we don't get any response after 1000 ms
|
||||
void Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
||||
if (BAD_SHORTADDR != shortaddr) {
|
||||
zigbee_devices.setReachable(shortaddr, false); // mark device as reachable
|
||||
zigbee_devices.getShortAddr(shortaddr).setReachable(false); // mark device as reachable
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1470,8 +1470,11 @@ void Z_IncomingMessage(class ZCLFrame &zcl_received) {
|
|||
// log the packet details
|
||||
zcl_received.log();
|
||||
|
||||
zigbee_devices.setLQI(srcaddr, linkquality != 0xFF ? linkquality : 0xFE); // EFR32 has a different scale for LQI
|
||||
zigbee_devices.setLastSeenNow(srcaddr);
|
||||
Z_Device & device = zigbee_devices.getShortAddr(srcaddr);
|
||||
if (srcaddr != localShortAddr) {
|
||||
device.setLQI(linkquality != 0xFF ? linkquality : 0xFE); // EFR32 has a different scale for LQI
|
||||
device.setLastSeenNow();
|
||||
}
|
||||
|
||||
char shortaddr[8];
|
||||
snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr);
|
||||
|
@ -1519,7 +1522,7 @@ void Z_IncomingMessage(class ZCLFrame &zcl_received) {
|
|||
|
||||
// since we just receveived data from the device, it is reachable
|
||||
zigbee_devices.resetTimersForDevice(srcaddr, 0 /* groupaddr */, Z_CAT_REACHABILITY); // remove any reachability timer already there
|
||||
zigbee_devices.setReachable(srcaddr, true); // mark device as reachable
|
||||
device.setReachable(true); // mark device as reachable
|
||||
|
||||
if (defer_attributes) {
|
||||
// Prepare for publish
|
||||
|
@ -1615,8 +1618,11 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) {
|
|||
if ((0x0000 == profileid) && (0x00 == srcendpoint)) {
|
||||
// ZDO request
|
||||
// Report LQI
|
||||
zigbee_devices.setLQI(srcaddr, linkquality);
|
||||
zigbee_devices.setLastSeenNow(srcaddr);
|
||||
Z_Device & device = zigbee_devices.getShortAddr(srcaddr);
|
||||
if (srcaddr != localShortAddr) {
|
||||
device.setLQI(linkquality);
|
||||
device.setLastSeenNow();
|
||||
}
|
||||
// Since ZDO messages start with a sequence number, we skip it
|
||||
// but we add the source address in the last 2 bytes
|
||||
SBuffer zdo_buf(buf.get8(20) - 1 + 2);
|
||||
|
|
|
@ -683,7 +683,7 @@ void CmndZbSend(void) {
|
|||
// parse "Device" and "Group"
|
||||
JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)];
|
||||
if (val_device) {
|
||||
device = zigbee_devices.parseDeviceParam(val_device.getStr());
|
||||
device = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
|
||||
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
}
|
||||
if (BAD_SHORTADDR == device) { // if not found, check if we have a group
|
||||
|
@ -828,7 +828,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
|
||||
// Information about source device: "Device", "Endpoint", "Cluster"
|
||||
// - the source endpoint must have a known IEEE address
|
||||
srcDevice = zigbee_devices.parseDeviceParam(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE), nullptr));
|
||||
srcDevice = zigbee_devices.parseDeviceFromName(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE), nullptr)).shortaddr;
|
||||
if (BAD_SHORTADDR == srcDevice) { ResponseCmndChar_P(PSTR("Unknown source device")); return; }
|
||||
// check if IEEE address is known
|
||||
uint64_t srcLongAddr = zigbee_devices.getDeviceLongAddr(srcDevice);
|
||||
|
@ -862,7 +862,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
|
||||
if ((dst_device) || (BAD_SHORTADDR != dstDevice)) {
|
||||
if (BAD_SHORTADDR == dstDevice) {
|
||||
dstDevice = zigbee_devices.parseDeviceParam(dst_device.getStr(nullptr));
|
||||
dstDevice = zigbee_devices.parseDeviceFromName(dst_device.getStr(nullptr)).shortaddr;
|
||||
if (BAD_SHORTADDR == dstDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
}
|
||||
if (0x0000 == dstDevice) {
|
||||
|
@ -941,7 +941,7 @@ void CmndZbUnbind(void) {
|
|||
|
||||
void CmndZbBindState_or_Map(uint16_t zdo_cmd) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr;
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
uint8_t index = XdrvMailbox.index - 1; // change default 1 to 0
|
||||
|
||||
|
@ -1002,7 +1002,7 @@ void CmndZbProbe(void) {
|
|||
//
|
||||
void CmndZbProbeOrPing(boolean probe) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr;
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
// everything is good, we can send the command
|
||||
|
@ -1034,19 +1034,19 @@ void CmndZbName(void) {
|
|||
|
||||
// check if parameters contain a comma ','
|
||||
char *p;
|
||||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
char *str = strtok_r(XdrvMailbox.data, ",", &p);
|
||||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p == nullptr) {
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, friendlyName ? friendlyName : "");
|
||||
const char * friendlyName = device.friendlyName;
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), device.shortaddr, friendlyName ? friendlyName : "");
|
||||
} else {
|
||||
if (strlen(p) > 32) { p[32] = 0x00; } // truncate to 32 chars max
|
||||
zigbee_devices.getShortAddr(shortaddr).setFriendlyName(p);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, p);
|
||||
device.setFriendlyName(p);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), device.shortaddr, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1066,18 +1066,18 @@ void CmndZbModelId(void) {
|
|||
|
||||
// check if parameters contain a comma ','
|
||||
char *p;
|
||||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
char *str = strtok_r(XdrvMailbox.data, ",", &p);
|
||||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p == nullptr) {
|
||||
const char * modelId = zigbee_devices.getModelId(shortaddr);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), shortaddr, modelId ? modelId : "");
|
||||
const char * modelId = device.modelId;
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), device.shortaddr, modelId ? modelId : "");
|
||||
} else {
|
||||
zigbee_devices.getShortAddr(shortaddr).setModelId(p);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), shortaddr, p);
|
||||
device.setModelId(p);
|
||||
Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), device.shortaddr, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,16 +1098,16 @@ void CmndZbLight(void) {
|
|||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p) {
|
||||
int8_t bulbtype = strtol(p, nullptr, 10);
|
||||
if (bulbtype > 5) { bulbtype = 5; }
|
||||
if (bulbtype < -1) { bulbtype = -1; }
|
||||
zigbee_devices.setLightProfile(shortaddr, bulbtype);
|
||||
device.setLightChannels(bulbtype);
|
||||
}
|
||||
String dump = zigbee_devices.dumpLightState(shortaddr);
|
||||
String dump = zigbee_devices.dumpLightState(device.shortaddr);
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_LIGHT "\":%s}"), dump.c_str());
|
||||
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_LIGHT));
|
||||
|
@ -1141,10 +1141,8 @@ void CmndZbOccupancy(void) {
|
|||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
int8_t occupancy_time = -1;
|
||||
if (p) {
|
||||
|
@ -1170,11 +1168,11 @@ void CmndZbOccupancy(void) {
|
|||
//
|
||||
void CmndZbForget(void) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
// everything is good, we can send the command
|
||||
if (zigbee_devices.removeDevice(shortaddr)) {
|
||||
if (zigbee_devices.removeDevice(device.shortaddr)) {
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Unknown device"));
|
||||
|
@ -1369,12 +1367,17 @@ void ZigbeeGlowPermitJoinLight(void) {
|
|||
void CmndZbStatus(void) {
|
||||
if (ZigbeeSerial) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
String dump;
|
||||
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data);
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device);
|
||||
} else {
|
||||
if (XdrvMailbox.index >= 2) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, *(Z_Device*)nullptr);
|
||||
}
|
||||
|
||||
String dump = zigbee_devices.dump(XdrvMailbox.index, shortaddr);
|
||||
Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -1502,9 +1505,8 @@ void CmndZbData(void) {
|
|||
}
|
||||
|
||||
for (auto device_name : root) {
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(device_name.getStr());
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
Z_Device & device = zigbee_devices.getShortAddr(shortaddr);
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(device_name.getStr());
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
JsonParserObject inner_data = device_name.getValue().getObject();
|
||||
if (inner_data) {
|
||||
if (!parseDeviceInnerData(device, inner_data)) {
|
||||
|
@ -1518,9 +1520,8 @@ void CmndZbData(void) {
|
|||
// non-JSON, export current data
|
||||
// ZbData 0x1234
|
||||
// ZbData Device_Name
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
const Z_Device & device = zigbee_devices.findShortAddr(shortaddr);
|
||||
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data);
|
||||
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
Z_attribute_list attr_data;
|
||||
|
||||
|
@ -1568,7 +1569,7 @@ void CmndZbData(void) {
|
|||
}
|
||||
|
||||
char hex[8];
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), device.shortaddr);
|
||||
Response_P(PSTR("{\"%s\":{\"%s\":%s}}"), XdrvMailbox.command, hex, attr_data.toString(true).c_str());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue