/* xdrv_23_zigbee_converters.ino - zigbee support for Tasmota Copyright (C) 2019 Theo Arends and Stephan Hadinger This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef USE_ZIGBEE //typedef int32_t (*Z_AttrConverter)(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param); typedef struct Z_CommandConverter { const char * tasmota_cmd; const char * zcl_cmd; } Z_CommandConverter; // list of post-processing directives const Z_CommandConverter Z_Commands[] = { { "Power", "0006!xx" }, // 0=Off, 1=On, 2=Toggle { "Dimmer", "0008!04/xx0A00" }, // Move to Level with On/Off, xx=0..254 (255 is invalid) { "Dimmer+", "0008!06/001902" }, // Step up by 10%, 0.2 secs { "Dimmer-", "0008!06/011902" }, // Step down by 10%, 0.2 secs { "DimmerStop", "0008!03" }, // Stop any Dimmer animation { "ResetAlarm", "0009!00/xxyyyy" }, // Reset alarm (alarm code + cluster identifier) { "ResetAllAlarms","0009!01" }, // Reset all alarms { "Hue", "0300!00/xx000A00" }, // Move to Hue, shortest time, 1s { "Sat", "0300!03/xx0A00" }, // Move to Sat { "HueSat", "0300!06/xxyy0A00" }, // Hue, Sat { "Color", "0300!07/xxxxyyyy0A00" }, // x, y (uint16) { "CT", "0300!0A/xxxx0A00" }, // Color Temperature Mireds (uint16) { "Shutter", "0102!xx" }, { "ShutterOpen", "0102!00"}, { "ShutterClose", "0102!01"}, { "ShutterStop", "0102!02"}, { "ShutterLift", "0102!05xx"}, // Lift percentage, 0%=open, 100%=closed { "ShutterTilt", "0102!08xx"}, // Tilt percentage }; const __FlashStringHelper* zigbeeFindCommand(const char *command) { char parm_uc[16]; // used to convert JSON keys to uppercase for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) { const Z_CommandConverter *conv = &Z_Commands[i]; if (0 == strcasecmp_P(command, conv->tasmota_cmd)) { return (const __FlashStringHelper*) conv->zcl_cmd; } } return nullptr; } inline bool isXYZ(char c) { return (c >= 'x') && (c <= 'z'); } // take the lower 4 bits and turn it to an hex char inline char hexDigit(uint32_t h) { uint32_t nybble = h & 0x0F; return (nybble > 9) ? 'A' - 10 + nybble : '0' + nybble; } // replace all xx/yy/zz substrings with unsigned ints, and the corresponding len (8, 16 or 32 bits) String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) { size_t len = strlen_P(zcl_cmd_P); char zcl_cmd[len+1]; strcpy_P(zcl_cmd, zcl_cmd_P); // copy into RAM char *p = zcl_cmd; while (*p) { if (isXYZ(*p) && (*p == *(p+1))) { // if char is [x-z] and followed by same char uint8_t val; switch (*p) { case 'x': val = x & 0xFF; x = x >> 8; break; case 'y': val = y & 0xFF; y = y >> 8; break; case 'z': val = z & 0xFF; z = z >> 8; break; } *p = hexDigit(val >> 4); *(p+1) = hexDigit(val); p++; } p++; } AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SendZCLCommand_P: zcl_cmd = %s"), zcl_cmd); return String(zcl_cmd); } const char kZ_Alias[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" "OPEN" "|" // 0 "ON|" D_ON "|" D_TRUE "|" D_START "|" "CLOSE" "|" // 1 "TOGGLE|" D_TOGGLE "|" // 2 "ALL" ; // 255 const uint8_t kZ_Numbers[] PROGMEM = { 0,0,0,0,0, 1,1,1,1,1, 2,2, 255 }; uint32_t ZigbeeAliasOrNumber(const char *state_text) { char command[16]; int state_number = GetCommandCode(command, sizeof(command), state_text, kZ_Alias); if (state_number >= 0) { // found an alias, get its value return pgm_read_byte(kZ_Numbers + state_number); } else { // no alias found, convert it as number return strtoul(state_text, nullptr, 0); } } #endif // USE_ZIGBEE