From bbf38e5db13e92b4570753d6b3f7f212e750d977 Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Fri, 13 Oct 2023 10:49:33 +0300 Subject: [PATCH] Add support for Shelly Pro 3EM (Gen2 EM devices in general) Closes #10 Still need to implement characteristics for these --- src/sensor.ts | 4 ++++ src/shelly.ts | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/sensor.ts b/src/sensor.ts index c380e62..5d3f034 100644 --- a/src/sensor.ts +++ b/src/sensor.ts @@ -11,6 +11,7 @@ export enum SensorType { export enum ShellyType { Gen1 = 'gen1', Gen2PM = 'gen2-pm', + Gen2EM = 'gen2-em', } export enum CharacteristicsSensorType { @@ -46,7 +47,10 @@ export interface IotawattCharacteristicsSensor extends CharacteristicsSensor { interface ShellySensorSettings { address: string type: undefined | ShellyType + // For Gen1 devices and Gen2 devices implementing the "Switch" component meter: number + // For devices implementing the "EM" component + phase: string | undefined } export interface ShellySensor extends PowerSensor { diff --git a/src/shelly.ts b/src/shelly.ts index d5680e4..ac8093a 100644 --- a/src/shelly.ts +++ b/src/shelly.ts @@ -11,20 +11,28 @@ type Gen1StatusResult = { meters: Gen1MeterResult[] } -type Gen2GetStatusResult = { +type Gen2SwitchGetStatusResult = { apower: number } +type Gen2EMGetStatusResult = { + a_act_power: number + b_act_power: number + c_act_power: number +} + const getSensorDataUrl = (sensor: ShellySensor): string => { const address = sensor.shelly.address const meter = sensor.shelly.meter // Request a different endpoint depending on what type of Shelly we're dealing with switch (sensor.shelly.type as ShellyType) { - case ShellyType.Gen2PM: - return `http://${address}/rpc/Switch.GetStatus?id=${meter}` case ShellyType.Gen1: return `http://${address}/status` + case ShellyType.Gen2PM: + return `http://${address}/rpc/Switch.GetStatus?id=${meter}` + case ShellyType.Gen2EM: + return `http://${address}/rpc/EM.GetStatus?id=${meter}` } } @@ -40,7 +48,7 @@ const parseGen1Response = (timestamp: number, circuit: Circuit, httpResponse: Ax } const parseGen2PMResponse = (timestamp: number, circuit: Circuit, httpResponse: AxiosResponse): PowerSensorData => { - const data = httpResponse.data as Gen2GetStatusResult + const data = httpResponse.data as Gen2SwitchGetStatusResult return { timestamp: timestamp, @@ -49,6 +57,30 @@ const parseGen2PMResponse = (timestamp: number, circuit: Circuit, httpResponse: } } +const parseGen2EMResponse = (timestamp: number, circuit: Circuit, httpResponse: AxiosResponse): PowerSensorData => { + const sensor = circuit.sensor as ShellySensor + const data = httpResponse.data as Gen2EMGetStatusResult + + let watts = 0 + switch (sensor.shelly.phase) { + case 'a': + watts = data.a_act_power + break + case 'b': + watts = data.b_act_power + break + case 'c': + watts = data.c_act_power + break + } + + return { + timestamp: timestamp, + circuit: circuit, + watts: watts, + } +} + export const getSensorData: PowerSensorPollFunction = async ( timestamp: number, circuit: Circuit, @@ -65,6 +97,8 @@ export const getSensorData: PowerSensorPollFunction = async ( return parseGen1Response(timestamp, circuit, httpResponse) case ShellyType.Gen2PM: return parseGen2PMResponse(timestamp, circuit, httpResponse) + case ShellyType.Gen2EM: + return parseGen2EMResponse(timestamp, circuit, httpResponse) } } catch (e) { console.error((e as Error).message)