mirror of https://github.com/arendst/Tasmota.git
Merge pull request #9689 from s-hadinger/zigbee_zboccupancy
Zigbee added ``ZbOccupancy`` command to configure the time-out for PIR
This commit is contained in:
commit
cfe52e6bd4
|
@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Zigbee reduce battery drain (#9642)
|
||||
- Zigbee added ``ZbMap`` command to describe Zigbee topology (#9651)
|
||||
- Command ``Gpios 255`` to show all possible GPIO configurations
|
||||
- Zigbee added ``ZbOccupancy`` command to configure the time-out for PIR
|
||||
|
||||
### Changed
|
||||
- PlatformIO library structure redesigned for compilation speed by Jason2866
|
||||
|
|
|
@ -577,6 +577,8 @@
|
|||
#define D_JSON_ZIGBEE_STATUS_MSG "StatusMessage"
|
||||
#define D_CMND_ZIGBEE_LIGHT "Light"
|
||||
#define D_JSON_ZIGBEE_LIGHT "Light"
|
||||
#define D_CMND_ZIGBEE_OCCUPANCY "Occupancy"
|
||||
#define D_JSON_ZIGBEE_OCCUPANCY "Occupancy"
|
||||
#define D_CMND_ZIGBEE_RESTORE "Restore"
|
||||
#define D_CMND_ZIGBEE_CONFIG "Config"
|
||||
#define D_JSON_ZIGBEE_CONFIG "Config"
|
||||
|
|
|
@ -172,7 +172,7 @@ void Z_Data_OnOff::setPower(bool val, uint32_t relay) {
|
|||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Device specific: Light device
|
||||
* Device specific: Plug device
|
||||
\*********************************************************************************************/
|
||||
class Z_Data_Plug : public Z_Data {
|
||||
public:
|
||||
|
@ -249,6 +249,18 @@ public:
|
|||
|
||||
/*********************************************************************************************\
|
||||
* Device specific: PIR
|
||||
*
|
||||
// List of occupancy time-outs:
|
||||
// 0xF = default (90 s)
|
||||
// 0x0 = no time-out
|
||||
// 0x1 = 15 s
|
||||
// 0x2 = 30 s
|
||||
// 0x3 = 45 s
|
||||
// 0x4 = 60 s
|
||||
// 0x5 = 75 s
|
||||
// 0x6 = 90 s -- default
|
||||
// 0x7 = 105 s
|
||||
// 0x8 = 120 s
|
||||
\*********************************************************************************************/
|
||||
class Z_Data_PIR : public Z_Data {
|
||||
public:
|
||||
|
@ -265,7 +277,10 @@ public:
|
|||
inline uint16_t getIlluminance(void) const { return illuminance; }
|
||||
|
||||
inline void setOccupancy(uint8_t _occupancy) { occupancy = _occupancy; }
|
||||
inline void setilluminance(uint16_t _illuminance) { illuminance = _illuminance; }
|
||||
inline void setIlluminance(uint16_t _illuminance) { illuminance = _illuminance; }
|
||||
|
||||
uint32_t getTimeoutSeconds(void) const;
|
||||
void setTimeoutSeconds(int32_t value);
|
||||
|
||||
static const Z_Data_Type type = Z_Data_Type::Z_PIR;
|
||||
// PIR
|
||||
|
@ -273,6 +288,24 @@ public:
|
|||
uint16_t illuminance; // illuminance
|
||||
};
|
||||
|
||||
uint32_t Z_Data_PIR::getTimeoutSeconds(void) const {
|
||||
if (_config != 0xF) {
|
||||
return _config * 15;
|
||||
} else {
|
||||
return 90;
|
||||
}
|
||||
}
|
||||
|
||||
void Z_Data_PIR::setTimeoutSeconds(int32_t value) {
|
||||
if (value < 0) {
|
||||
_config = 0xF;
|
||||
} else {
|
||||
uint32_t val_15 = (value + 14)/ 15; // always round up
|
||||
if (val_15 > 8) { val_15 = 8; }
|
||||
_config = val_15;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Device specific: Sensors: temp, humidity, pressure...
|
||||
\*********************************************************************************************/
|
||||
|
@ -510,6 +543,7 @@ public:
|
|||
inline bool getReachable(void) const { return reachable; }
|
||||
inline bool getPower(uint8_t ep =0) const;
|
||||
|
||||
bool addEndpoint(uint8_t endpoint);
|
||||
// dump device attributes to ZbData
|
||||
void toAttributes(Z_attribute_list & attr_list) const;
|
||||
|
||||
|
|
|
@ -228,21 +228,27 @@ void Z_Devices::clearEndpoints(uint16_t shortaddr) {
|
|||
|
||||
//
|
||||
// Add an endpoint to a shortaddr
|
||||
// return true if a change was made
|
||||
//
|
||||
void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
|
||||
if ((0x00 == endpoint) || (endpoint > 240)) { return; }
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
bool Z_Device::addEndpoint(uint8_t endpoint) {
|
||||
if ((0x00 == endpoint) || (endpoint > 240)) { return false; }
|
||||
|
||||
for (uint32_t i = 0; i < endpoints_max; i++) {
|
||||
if (endpoint == device.endpoints[i]) {
|
||||
return; // endpoint already there
|
||||
if (endpoint == endpoints[i]) {
|
||||
return false; // endpoint already there
|
||||
}
|
||||
if (0 == device.endpoints[i]) {
|
||||
device.endpoints[i] = endpoint;
|
||||
dirty();
|
||||
return;
|
||||
if (0 == endpoints[i]) {
|
||||
endpoints[i] = endpoint;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
|
||||
if (getShortAddr(shortaddr).addEndpoint(endpoint)) {
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -265,7 +265,7 @@ void hydrateSingleDevice(const SBuffer & buf_d, uint32_t version) {
|
|||
uint8_t ep = buf_d.get8(d++);
|
||||
if (0xFF == ep) { break; } // ep 0xFF marks the end of the endpoints
|
||||
if (ep > 240) { ep = 0xFF; } // ep == 0xFF means ignore
|
||||
if ((ep > 0) && (ep != 0xFF)) { zigbee_devices.addEndpoint(shortaddr, ep); } // don't add endpoint if it is 0x00
|
||||
device.addEndpoint(ep); // it will ignore invalid endpoints
|
||||
while (d < buf_len) {
|
||||
uint8_t config_type = buf_d.get8(d++);
|
||||
if (0xFF == config_type) { break; } // 0xFF marks the end of congiguration
|
||||
|
|
|
@ -1285,7 +1285,12 @@ void ZCLFrame::generateCallBacks(Z_attribute_list& attr_list) {
|
|||
case 0x04060000: // Occupancy
|
||||
uint32_t occupancy = attr.getUInt();
|
||||
if (occupancy) {
|
||||
zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, _cluster_id, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
|
||||
uint32_t pir_timer = OCCUPANCY_TIMEOUT;
|
||||
const Z_Data_PIR & pir_found = (const Z_Data_PIR&) zigbee_devices.getShortAddr(_srcaddr).data.find(Z_Data_Type::Z_PIR, _srcendpoint);
|
||||
if (&pir_found != nullptr) {
|
||||
pir_timer = pir_found.getTimeoutSeconds() * 1000;
|
||||
}
|
||||
zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, pir_timer, _cluster_id, _srcendpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback);
|
||||
} else {
|
||||
zigbee_devices.resetTimersForDevice(_srcaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
|
|||
D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" D_CMND_ZIGBEE_PROBE "|"
|
||||
D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|"
|
||||
D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|"
|
||||
D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" D_CMND_ZIGBEE_MAP "|"
|
||||
D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_OCCUPANCY "|"
|
||||
D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" D_CMND_ZIGBEE_MAP "|"
|
||||
D_CMND_ZIGBEE_CONFIG "|" D_CMND_ZIGBEE_DATA
|
||||
;
|
||||
|
||||
|
@ -47,7 +48,8 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
|
|||
&CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe,
|
||||
&CmndZbForget, &CmndZbSave, &CmndZbName,
|
||||
&CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId,
|
||||
&CmndZbLight, &CmndZbRestore, &CmndZbBindState, &CmndZbMap,
|
||||
&CmndZbLight, &CmndZbOccupancy,
|
||||
&CmndZbRestore, &CmndZbBindState, &CmndZbMap,
|
||||
&CmndZbConfig, CmndZbData,
|
||||
};
|
||||
|
||||
|
@ -1111,6 +1113,56 @@ void CmndZbLight(void) {
|
|||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_LIGHT));
|
||||
ResponseCmndDone();
|
||||
}
|
||||
//
|
||||
// Command `ZbOccupancy`
|
||||
// Specify, read or erase the Occupancy detector configuration
|
||||
void CmndZbOccupancy(void) {
|
||||
// Syntax is:
|
||||
// ZbOccupancy <device_id>,<x> - set the occupancy time-out
|
||||
// ZbOccupancy <device_id> - display the configuration
|
||||
//
|
||||
// List of occupancy time-outs:
|
||||
// 0xF = default (90 s)
|
||||
// 0x0 = no time-out
|
||||
// 0x1 = 15 s
|
||||
// 0x2 = 30 s
|
||||
// 0x3 = 45 s
|
||||
// 0x4 = 60 s
|
||||
// 0x5 = 75 s
|
||||
// 0x6 = 90 s -- default
|
||||
// 0x7 = 105 s
|
||||
// 0x8 = 120 s
|
||||
// Where <device_id> can be: short_addr, long_addr, device_index, friendly_name
|
||||
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
|
||||
// check if parameters contain a comma ','
|
||||
char *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.getShortAddr(shortaddr);
|
||||
|
||||
int8_t occupancy_time = -1;
|
||||
if (p) {
|
||||
Z_Data_PIR & pir = (Z_Data_PIR&) device.data.getByType(Z_Data_Type::Z_PIR);
|
||||
occupancy_time = strtol(p, nullptr, 10);
|
||||
pir.setTimeoutSeconds(occupancy_time);
|
||||
zigbee_devices.dirty();
|
||||
} else {
|
||||
const Z_Data_PIR & pir_found = (const Z_Data_PIR&) device.data.find(Z_Data_Type::Z_PIR);
|
||||
if (&pir_found != nullptr) {
|
||||
occupancy_time = pir_found.getTimeoutSeconds();
|
||||
}
|
||||
}
|
||||
Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_OCCUPANCY "\":%d}"), occupancy_time);
|
||||
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_LIGHT));
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
//
|
||||
// Command `ZbForget`
|
||||
|
@ -1357,6 +1409,7 @@ bool parseDeviceInnerData(class Z_Device & device, JsonParserObject root) {
|
|||
if (val = data_values[PSTR("LastSeen")]) { device.last_seen = val.getUInt(); }
|
||||
} else {
|
||||
// Import generic attributes first
|
||||
device.addEndpoint(endpoint);
|
||||
Z_Data & data = device.data.getByType(data_type, endpoint);
|
||||
|
||||
// scan through attributes
|
||||
|
@ -1459,6 +1512,7 @@ void CmndZbData(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
zigbee_devices.dirty(); // save to flash
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
// non-JSON, export current data
|
||||
|
|
Loading…
Reference in New Issue