Created
April 13, 2025 09:22
-
-
Save marazmarci/a80ca373d247863983cef2266fb2914e to your computer and use it in GitHub Desktop.
SODA S8 Window Handle Zigbee2MQTT external converter v1: cached state
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const exposes = require("zigbee-herdsman-converters/lib/exposes"); | |
| const tuya = require("zigbee-herdsman-converters/lib/tuya"); | |
| const e = exposes.presets; | |
| const ea = exposes.access; | |
| const globalStore = require("zigbee-herdsman-converters/lib/store"); | |
| const fz = { | |
| TZE200_j7sgd8po_SODA_S8: { | |
| ...tuya.fz.datapoints, | |
| convert: (model, msg, publish, options, meta) => { | |
| // The SODA S8 window handle reports its state in two consecutive messages. | |
| // The first includes button states, while the second does not. | |
| // To prevent button states from being lost in the published state, we store the last known values in `globalStore` | |
| // and reapply them when the second message arrives without button state data. | |
| // Note: Button press/release events send a single message containing only the relevant datapoint. | |
| const result = tuya.fz.datapoints.convert(model, msg, publish, options, meta); | |
| console.debug("[SODA S8 Window Handle] result of tuya.fz.datapoints.convert:", result); | |
| if (!result) return; | |
| const cachedState = globalStore.getValue(msg.device, "cachedState", { | |
| button_left: "released", button_right: "released", duration: 180 | |
| }); | |
| // Update stored cached states if included in the message | |
| if (result.button_left !== undefined) { | |
| cachedState.button_left = result.button_left; | |
| console.debug("[SODA S8 Window Handle] result.button_left !== undefined"); | |
| } | |
| if (result.button_right !== undefined) { | |
| cachedState.button_right = result.button_right; | |
| console.debug("[SODA S8 Window Handle] result.button_right !== undefined"); | |
| } | |
| if (result.duration !== undefined) { | |
| cachedState.duration = result.duration; | |
| console.debug("[SODA S8 Window Handle] result.duration !== undefined"); | |
| } | |
| // Save updated button states back to global store | |
| globalStore.putValue(msg.device, "cachedState", cachedState); | |
| // Merge stored button states with the current message | |
| const mergedResult = { | |
| ...result, | |
| button_left: cachedState.button_left, | |
| button_right: cachedState.button_right, | |
| duration: cachedState.duration, | |
| }; | |
| console.debug("[SODA S8 Window Handle] mergedResult", mergedResult); | |
| return mergedResult; | |
| }, | |
| }, | |
| }; | |
| module.exports = { | |
| fingerprint: tuya.fingerprint("TS0601", ["_TZE200_j7sgd8po"]), | |
| model: "S8", | |
| vendor: "SODA", | |
| description: "S8 premium window handle EXT v1: cached state", | |
| toZigbee: [tuya.tz.datapoints], | |
| fromZigbee: [fz.TZE200_j7sgd8po_SODA_S8], | |
| configure: tuya.configureMagicPacket, | |
| exposes: [ | |
| e.battery(), | |
| e.battery_low(), | |
| e.binary("vacation", ea.STATE_SET, "ON", "OFF").withDescription("Vacation mode"), | |
| e.enum("alarm", ea.STATE, ["ALARM", "IDLE"]).withDescription("Alarm"), | |
| e.binary("alarm_switch", ea.STATE_SET, "ON", "OFF").withDescription("Alarm enable"), | |
| e.binary("handlesound", ea.STATE_SET, "ON", "OFF").withDescription("Handle closed sound"), | |
| e.enum("opening_mode", ea.STATE, ["closed", "tilted"]).withDescription("Window tilt"), | |
| e.temperature(), | |
| e.humidity(), | |
| e.binary("keysound", ea.STATE_SET, "ON", "OFF").withDescription("Key beep sound"), | |
| e.enum("sensitivity", ea.STATE_SET, ["off", "low", "medium", "high", "max"]).withDescription("Sensitivity of the alarm sensor"), | |
| e.enum("position", ea.STATE, ["up", "right", "down", "left"]), | |
| e.enum("button_left", ea.STATE, ["released", "pressed"]), | |
| e.enum("button_right", ea.STATE, ["released", "pressed"]), | |
| e.numeric("duration", ea.STATE_SET).withValueMin(0).withValueMax(300).withValueStep(1).withUnit("sec").withDescription("Duration of the alarm").withPreset("default", 180, "Default value"), | |
| e.numeric("update_frequency", ea.STATE_SET).withUnit("min").withDescription("Update frequency").withValueMin(0).withValueMax(700).withPreset("default", 20, "Default value"), | |
| e.enum("calibrate", ea.STATE_SET, ["clear", "execute"]), | |
| ], | |
| meta: { | |
| tuyaDatapoints: [ | |
| [3, "battery", tuya.valueConverter.raw], | |
| [8, "temperature", tuya.valueConverter.divideBy10], | |
| [101, "humidity", tuya.valueConverter.raw], | |
| [102, "alarm", tuya.valueConverterBasic.lookup({IDLE: tuya.enum(0), ALARM: tuya.enum(1),}),], | |
| [103, "opening_mode", tuya.valueConverterBasic.lookup({closed: tuya.enum(0), tilted: tuya.enum(1),}),], | |
| [104, "position", tuya.valueConverterBasic.lookup({left: tuya.enum(4), up: tuya.enum(1), down: tuya.enum(2), right: tuya.enum(3),}),], | |
| [105, "button_left", tuya.valueConverterBasic.lookup({released: tuya.enum(0), pressed: tuya.enum(1),}),], | |
| [106, "button_right", tuya.valueConverterBasic.lookup({released: tuya.enum(0), pressed: tuya.enum(1),}),], | |
| [107, "vacation", tuya.valueConverterBasic.lookup({OFF: tuya.enum(0), ON: tuya.enum(1),}),], | |
| [108, "sensitivity", tuya.valueConverterBasic.lookup({off: tuya.enum(0), low: tuya.enum(1), medium: tuya.enum(2), high: tuya.enum(3), max: tuya.enum(4),}),], | |
| [109, "alarm_switch", tuya.valueConverterBasic.lookup({OFF: tuya.enum(0), ON: tuya.enum(1),}),], | |
| [110, "update_frequency", tuya.valueConverter.raw], | |
| [111, "keysound", tuya.valueConverterBasic.lookup({OFF: tuya.enum(0), ON: tuya.enum(1),}),], | |
| [112, "battery_low", tuya.valueConverterBasic.lookup({ON: tuya.enum(0), OFF: tuya.enum(1),}),], | |
| [113, "duration", tuya.valueConverter.raw], | |
| [114, "handlesound", tuya.valueConverterBasic.lookup({OFF: tuya.enum(0), ON: tuya.enum(1),}),], | |
| [120, "calibrate", tuya.valueConverterBasic.lookup({clear: tuya.enum(0), execute: tuya.enum(1),}),], | |
| ], | |
| }, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment