From f54998353526655d2cf4bd923017c1297fa5376a Mon Sep 17 00:00:00 2001 From: Alexander Romashev Date: Tue, 7 Feb 2023 01:15:47 +0300 Subject: [PATCH] Add support for Mi Smart Humidifier 2 (#117) --- .github/assets/deerma-humidifier-jsq2w.jpg | Bin 0 -> 27217 bytes README.md | 12 ++- config.schema.json | 1 + src/devices/models/deerma-jsq2w.ts | 118 +++++++++++++++++++++ src/devices/models/index.ts | 3 + 5 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 .github/assets/deerma-humidifier-jsq2w.jpg create mode 100644 src/devices/models/deerma-jsq2w.ts diff --git a/.github/assets/deerma-humidifier-jsq2w.jpg b/.github/assets/deerma-humidifier-jsq2w.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bb2d1a4e86ab771942da4337697319ed263a5ef GIT binary patch literal 27217 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 yJa6|me8jiMN!)X!e&@l6r49eyYep;q^Y- `zhimi.humidifier.v1`
- `zhimi.humidifier.ca1`
- `zhimi.humidifier.cb1`
- `zhimi.humidifier.ca4`
- `deerma.humidifier.mjjsq`
- `deerma.humidifier.jsq1`
- `deerma.humidifier.jsq3`
- `deerma.humidifier.jsq4`
- `deerma.humidifier.jsq5`
- `deerma.humidifier.jsqs`
- `shuii.humidifier.jsq001`
See [supported devices](#supported-devices) section for more details. | — | +| model | One of:
- `zhimi.humidifier.v1`
- `zhimi.humidifier.ca1`
- `zhimi.humidifier.cb1`
- `zhimi.humidifier.ca4`
- `deerma.humidifier.mjjsq`
- `deerma.humidifier.jsq2w`
- `deerma.humidifier.jsq1`
- `deerma.humidifier.jsq3`
- `deerma.humidifier.jsq4`
- `deerma.humidifier.jsq5`
- `deerma.humidifier.jsqs`
- `shuii.humidifier.jsq001`
See [supported devices](#supported-devices) section for more details. | — | | updateInterval | Device values update interval in seconds. This value affects how often data (humidity, temperature, etc.) from the device is updated. | 30 | | disabled | Disable the devices. Can be used to temporary hide the device when it is not required without removing it from config. | false | | autoSwitchToHumidityMode | Automatically switches mode to "humidity" when target humidity is changed. Affects models:
- `zhimi.humidifier.{ca1,cb1,ca4}`
- `deerma.humidifier.{mjjsq,jsq1,jsq001,jsqs,jsq3,jsq4,jsq5}` | false | @@ -87,7 +87,7 @@ Add the following part to the "platforms" section of your [Homebridge config](ht ## Supported devices -### Smartmi Humidifier +### Smartmi Humidifier Model: `zhimi.humidifier.v1` @@ -127,6 +127,14 @@ Model №: SCK0A45, ZNJSQ01DEM, MJJSQ03DY +### Mi Smart Humidifier 2 + +Model: `deerma.humidifier.jsq2w` + +Model №: MJJSQ05DY + + + ### Mijia Pure Smart Humidifier Model: `deerma.humidifier.jsq4` diff --git a/config.schema.json b/config.schema.json index 6ea847c..5b56f5d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -39,6 +39,7 @@ "zhimi.humidifier.ca4", "deerma.humidifier.mjjsq", "deerma.humidifier.jsq1", + "deerma.humidifier.jsq2w", "deerma.humidifier.jsq3", "deerma.humidifier.jsq4", "deerma.humidifier.jsq5", diff --git a/src/devices/models/deerma-jsq2w.ts b/src/devices/models/deerma-jsq2w.ts new file mode 100644 index 0000000..afe50d0 --- /dev/null +++ b/src/devices/models/deerma-jsq2w.ts @@ -0,0 +1,118 @@ +import type * as hb from "homebridge"; +import * as miio from "miio-api"; +import { MiotProtocol, MiotArg } from "../protocols"; +import { DeviceOptions } from "../../platform"; +import { ValueOf } from "../utils"; +import { Features } from "../features"; +import { HumidifierConfig } from "."; + +enum Mode { + Level1 = 1, + Level2 = 2, + Level3 = 3, + Humidity = 4, +} + +type Props = { + power: boolean; + fan_level: Mode; + target_humidity: number; + temperature: number; + relative_humidity: number; + switch_status: boolean; + buzzer: boolean; +}; + +class Proto extends MiotProtocol { + protected getCallArg(key: keyof Props): MiotArg { + return this.callArgs(key, null); + } + + protected setCallArg(key: keyof Props, value: ValueOf): MiotArg { + return this.callArgs(key, value); + } + + private callArgs(key: keyof Props, value: ValueOf | null): MiotArg { + const common = { did: key, value }; + + switch (key) { + case "power": + return { ...common, siid: 2, piid: 1 }; + case "fan_level": + return { ...common, siid: 2, piid: 5 }; + case "target_humidity": + return { ...common, siid: 2, piid: 6 }; + case "relative_humidity": + return { ...common, siid: 3, piid: 1 }; + case "switch_status": + return { ...common, siid: 6, piid: 1 }; + case "buzzer": + return { ...common, siid: 5, piid: 1 }; + case "temperature": + return { ...common, siid: 3, piid: 7 }; + } + } +} + +export function deermaJSQ2W( + device: miio.Device, + feat: Features, + log: hb.Logging, + options: DeviceOptions, +): HumidifierConfig { + return { + protocol: new Proto(device), + features: [ + feat.targetState(), + feat.currentState("power", { on: true, off: false }), + feat.active("power", "set_properties", { on: true, off: false }), + feat.rotationSpeed("fan_level", "set_properties", { + modes: [Mode.Level1, Mode.Level2, Mode.Level3, Mode.Humidity], + }), + feat.humidity("relative_humidity"), + ...(options.ledBulb?.enabled + ? feat.ledBulb("switch_status", "set_properties", { + name: options.ledBulb.name, + modes: [true, false], + on: true, + off: false, + }) + : []), + + ...(!options.disableTargetHumidity + ? [ + feat.humidityThreshold("target_humidity", "set_properties", { + min: 40, + max: 70, + switchToMode: options.autoSwitchToHumidityMode + ? { + key: "fan_level", + call: "set_properties", + value: Mode.Humidity, + } + : undefined, + }), + ] + : []), + + ...(options.buzzerSwitch?.enabled + ? feat.buzzerSwitch("buzzer", "set_properties", { + name: options.buzzerSwitch.name, + on: true, + off: false, + }) + : []), + ...(options.temperatureSensor?.enabled + ? feat.temperatureSensor("temperature", { + name: options.temperatureSensor.name, + toChar: (it) => it, + }) + : []), + ...(options.humiditySensor?.enabled + ? feat.humiditySensor("relative_humidity", { + name: options.humiditySensor.name, + }) + : []), + ], + }; +} \ No newline at end of file diff --git a/src/devices/models/index.ts b/src/devices/models/index.ts index 2995ec0..d20c41a 100644 --- a/src/devices/models/index.ts +++ b/src/devices/models/index.ts @@ -6,6 +6,7 @@ import { zhimiV1 } from "./zhimi-v1"; import { zhimiCA1, zhimiCB1 } from "./zhimi-cab1"; import { zhimiCA4 } from "./zhimi-ca4"; import { deermaMJJSQ } from "./deerma-mjjsq"; +import { deermaJSQ2W as deermaJSQ2W } from "./deerma-jsq2w"; import { deermaJSQ4 } from "./deerma-jsq4"; import { deermaJSQ5 } from "./deerma-jsq5"; import { shuiiJSQ001 } from "./shuii-jsq001"; @@ -31,6 +32,7 @@ export enum HumidifierModel { ZHIMI_CA4 = "zhimi.humidifier.ca4", DEERMA_MJJSQ = "deerma.humidifier.mjjsq", DEERMA_JSQ = "deerma.humidifier.jsq1", + DEERMA_JSQ2W = "deerma.humidifier.jsq2w", DEERMA_JSQ4 = "deerma.humidifier.jsq4", DEERMA_JSQ3 = "deerma.humidifier.jsq3", DEERMA_JSQ5 = "deerma.humidifier.jsq5", @@ -45,6 +47,7 @@ export const HumidifierFactory = { [HumidifierModel.ZHIMI_CA4]: zhimiCA4, [HumidifierModel.DEERMA_MJJSQ]: deermaMJJSQ, [HumidifierModel.DEERMA_JSQ]: deermaMJJSQ, + [HumidifierModel.DEERMA_JSQ2W]: deermaJSQ2W, [HumidifierModel.DEERMA_JSQ4]: deermaJSQ4, [HumidifierModel.DEERMA_JSQ3]: deermaJSQ5, [HumidifierModel.DEERMA_JSQ5]: deermaJSQ5,