diff --git a/.github/assets/deerma-humidifier-jsq2w.jpg b/.github/assets/deerma-humidifier-jsq2w.jpg new file mode 100644 index 0000000..5bb2d1a Binary files /dev/null and b/.github/assets/deerma-humidifier-jsq2w.jpg differ diff --git a/README.md b/README.md index db7c4fa..08d2165 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Add the following part to the "platforms" section of your [Homebridge config](ht | name | Name of the device. This will appear in your Home app. | "Humidifier" | | address | IP address of the device. | — | | token | Device token. See [obtaining token](https://github.com/Maxmudjon/com.xiaomi-miio/blob/master/docs/obtain_token.md). | — | -| model | One of:
- `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,