Skip to content

Commit

Permalink
Shelly: Enable Pro 3EM in monophase mode (evcc-io#17219)
Browse files Browse the repository at this point in the history
  • Loading branch information
thierolm authored Nov 13, 2024
1 parent 964adbe commit 6836749
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 22 deletions.
4 changes: 4 additions & 0 deletions meter/shelly/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type Connection struct {
channel int
gen int // Shelly api generation
devicetype string // Shelly device type
app string // Shelly device app code
profile string // Shelly device profile
}

// NewConnection creates a new Shelly device connection.
Expand All @@ -45,6 +47,8 @@ func NewConnection(uri, user, password string, channel int) (*Connection, error)
channel: channel,
gen: resp.Gen,
devicetype: resp.Type,
app: resp.App,
profile: resp.Profile,
}

conn.Client.Transport = request.NewTripper(log, transport.Insecure())
Expand Down
34 changes: 24 additions & 10 deletions meter/shelly/switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,25 @@ func (sh *Switch) CurrentPower() (float64, error) {
}

default:
var resem Gen2EmStatusResponse
var res Gen2StatusResponse
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
return 0, err
if d.app == "Pro3EM" && d.profile == "monophase" {
if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil {
return 0, err
}
} else {
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
return 0, err
}
}

switch d.channel {
case 1:
power = res.Switch1.Apower + res.Pm1.Apower
power = res.Switch1.Apower + res.Pm1.Apower + resem.Em1.ActPower
case 2:
power = res.Switch2.Apower + res.Pm2.Apower
power = res.Switch2.Apower + res.Pm2.Apower + resem.Em2.ActPower
default:
power = res.Switch0.Apower + res.Pm0.Apower
power = res.Switch0.Apower + res.Pm0.Apower + resem.Em0.ActPower
}
}

Expand Down Expand Up @@ -123,18 +130,25 @@ func (sh *Switch) TotalEnergy() (float64, error) {
energy = gen1Energy(d.devicetype, energy)

default:
var resem Gen2EmStatusResponse
var res Gen2StatusResponse
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
return 0, err
if d.app == "Pro3EM" && d.profile == "monophase" {
if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil {
return 0, err
}
} else {
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
return 0, err
}
}

switch d.channel {
case 1:
energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total
energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total + resem.Em1Data.TotalActEnergy - resem.Em1Data.TotalActRetEnergy
case 2:
energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total
energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total + resem.Em2Data.TotalActEnergy - resem.Em2Data.TotalActRetEnergy
default:
energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total
energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total + resem.Em0Data.TotalActEnergy - resem.Em0Data.TotalActRetEnergy
}
}

Expand Down
39 changes: 29 additions & 10 deletions meter/shelly/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ type DeviceInfo struct {
Model string `json:"model"`
Type string `json:"type"`
Mac string `json:"mac"`
App string `json:"app"`
Auth bool `json:"auth"`
AuthEn bool `json:"auth_en"`
NumMeters int `json:"num_meters"`
Profile string `json:"profile"`
}

type Gen2RpcPost struct {
Expand Down Expand Up @@ -40,17 +42,34 @@ type Gen2StatusResponse struct {
Pm2 Gen2Switch `json:"pm3:2"`
}

type Gen2Em struct {
Current float64 `json:"current"`
Voltage float64 `json:"voltage"`
ActPower float64 `json:"act_power"`
}

type Gen2EmData struct {
TotalActEnergy float64 `json:"total_act_energy"`
TotalActRetEnergy float64 `json:"total_act_ret_energy"`
}

type Gen2EmStatusResponse struct {
TotalPower float64 `json:"total_act_power"`
CurrentA float64 `json:"a_current"`
CurrentB float64 `json:"b_current"`
CurrentC float64 `json:"c_current"`
VoltageA float64 `json:"a_voltage"`
VoltageB float64 `json:"b_voltage"`
VoltageC float64 `json:"c_voltage"`
PowerA float64 `json:"a_act_power"`
PowerB float64 `json:"b_act_power"`
PowerC float64 `json:"c_act_power"`
TotalPower float64 `json:"total_act_power"`
CurrentA float64 `json:"a_current"`
CurrentB float64 `json:"b_current"`
CurrentC float64 `json:"c_current"`
VoltageA float64 `json:"a_voltage"`
VoltageB float64 `json:"b_voltage"`
VoltageC float64 `json:"c_voltage"`
PowerA float64 `json:"a_act_power"`
PowerB float64 `json:"b_act_power"`
PowerC float64 `json:"c_act_power"`
Em0 Gen2Em `json:"em1:0"`
Em1 Gen2Em `json:"em1:1"`
Em2 Gen2Em `json:"em1:2"`
Em0Data Gen2EmData `json:"em1data:0"`
Em1Data Gen2EmData `json:"em1data:1"`
Em2Data Gen2EmData `json:"em1data:2"`
}

type Gen2EmDataStatusResponse struct {
Expand Down
40 changes: 40 additions & 0 deletions meter/shelly/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,44 @@ func TestUnmarshalGen2StatusResponse(t *testing.T) {
assert.Equal(t, 3551.682, res.Pm0.Aenergy.Total)
assert.Equal(t, 1780.1, res.Pm0.Apower)
}

{
// Shelly Pro 3EM
var res Gen2EmStatusResponse

jsonstr := `{"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":3.705,"voltage":242.8,"act_power":598.9,"aprt_power":900.6,"pf":0.66,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.194,"voltage":242.8,"act_power":0.0,"aprt_power":47.2,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1:2":{"id":2,"current":0.027,"voltage":242.8,"act_power":0.0,"aprt_power":6.6,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":3458.24,"total_act_ret_energy":1605.24},"em1data:1":{"id":1,"total_act_energy":2768.67,"total_act_ret_energy":25.49},"em1data:2":{"id":2,"total_act_energy":3.09,"total_act_ret_energy":0.71},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"sys":{"mac":"FCE8C0DBA850","restart_required":false,"time":"19:46","unixtime":1731404780,"uptime":563,"ram_size":247148,"ram_free":110596,"fs_size":524288,"fs_free":176128,"cfg_rev":21,"kvs_rev":0,"schedule_rev":3,"webhook_rev":1,"available_updates":{},"reset_reason":3},"temperature:0":{"id": 0,"tC":39.0, "tF":102.2},"wifi":{"sta_ip":"192.168.40.174","status":"got ip","ssid":"IoT","rssi":-67},"ws":{"connected":false}}`
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
// Channel 0 (1)
assert.Equal(t, 598.9, res.Em0.ActPower)
assert.Equal(t, 3.705, res.Em0.Current)
assert.Equal(t, 242.8, res.Em0.Voltage)
assert.Equal(t, 3458.24, res.Em0Data.TotalActEnergy)
assert.Equal(t, 1605.24, res.Em0Data.TotalActRetEnergy)
// Channel 1 (2)
assert.Equal(t, 0.0, res.Em1.ActPower)
assert.Equal(t, 0.194, res.Em1.Current)
assert.Equal(t, 242.8, res.Em1.Voltage)
assert.Equal(t, 2768.67, res.Em1Data.TotalActEnergy)
assert.Equal(t, 25.49, res.Em1Data.TotalActRetEnergy)
// Channel 2 (3)
assert.Equal(t, 0.0, res.Em2.ActPower)
assert.Equal(t, 0.027, res.Em2.Current)
assert.Equal(t, 242.8, res.Em2.Voltage)
assert.Equal(t, 3.09, res.Em2Data.TotalActEnergy)
assert.Equal(t, 0.71, res.Em2Data.TotalActRetEnergy)
}
}

// Test Shelly device info
func TestUnmarshalDeviceInfoResponse(t *testing.T) {
{
// Shelly Pro 3EM
var res DeviceInfo

jsonstr := `{"name":null,"id":"shellypro3em-fce8c0dba900","mac":"FCE8C0DBA900","slot":1,"model":"SPEM-003CEBEU","gen":2,"fw_id":"20241011-114455/1.4.4-g6d2a586","ver":"1.4.4","app":"Pro3EM","auth_en":false,"auth_domain":null,"profile":"monophase"}`
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))

assert.Equal(t, "Pro3EM", res.App)
assert.Equal(t, "monophase", res.Profile)
}
}
4 changes: 2 additions & 2 deletions templates/definition/meter/shelly-1pm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ template: shelly-1pm
products:
- brand: Shelly
description:
generic: 1PM, EM, Plug S
generic: 1PM, EM, Plug S, Pro 3EM in monophase mode
group: switchsockets
params:
- name: usage
choice: ["pv", "charge"]
choice: ["grid", "pv", "charge"]
- name: host
- name: user
- name: password
Expand Down

0 comments on commit 6836749

Please sign in to comment.