Skip to content

Commit 236c88f

Browse files
authored
Merge pull request #239 from plugwise/p1-3ph
P1: add 3-phase support
2 parents d477cf7 + 27d0e51 commit 236c88f

File tree

8 files changed

+181
-6
lines changed

8 files changed

+181
-6
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
# v0.26.0: Smile P1: add support for 3-phase DSMR
4+
- Add support for the P1 4.4.0-beta firmware
5+
36
# v0.26.9: Hide cooling-related switch, binary_sensors when there is no cooling present
47
- This fixes the unexpected appearance of new entities after the Adam 3.7.1 firmware-update
58
- Properly handle an empty schedule, should fix #313

plugwise/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Plugwise module."""
22

3-
__version__ = "0.25.9"
3+
__version__ = "0.26.0"
44

55
from plugwise.smile import Smile
66
from plugwise.stick import Stick

plugwise/constants.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
ATTR_STATE_CLASS: Final = "state_class"
1616
ATTR_UNIT_OF_MEASUREMENT: Final = "unit_of_measurement"
1717
DEGREE: Final = "°"
18+
ELECTRIC_POTENTIAL_VOLT: Final = "V"
1819
ENERGY_KILO_WATT_HOUR: Final = "kWh"
1920
ENERGY_WATT_HOUR: Final = "Wh"
2021
PERCENTAGE: Final = "%"
@@ -444,7 +445,16 @@
444445
P1_MEASUREMENTS: Final[dict[str, UOM]] = {
445446
"electricity_consumed": UOM(POWER_WATT),
446447
"electricity_produced": UOM(POWER_WATT),
448+
"electricity_phase_one_consumed": UOM(POWER_WATT),
449+
"electricity_phase_two_consumed": UOM(POWER_WATT),
450+
"electricity_phase_three_consumed": UOM(POWER_WATT),
451+
"electricity_phase_one_produced": UOM(POWER_WATT),
452+
"electricity_phase_two_produced": UOM(POWER_WATT),
453+
"electricity_phase_three_produced": UOM(POWER_WATT),
447454
"gas_consumed": UOM(VOLUME_CUBIC_METERS),
455+
"voltage_phase_one": UOM(ELECTRIC_POTENTIAL_VOLT),
456+
"voltage_phase_two": UOM(ELECTRIC_POTENTIAL_VOLT),
457+
"voltage_phase_three": UOM(ELECTRIC_POTENTIAL_VOLT),
448458
}
449459
# Thermostat and Plug/Stretch related measurements
450460
# Excluded:
@@ -558,6 +568,12 @@
558568
"electricity_consumed_peak_interval",
559569
"electricity_consumed_peak_point",
560570
"electricity_consumed_point",
571+
"electricity_phase_one_consumed",
572+
"electricity_phase_two_consumed",
573+
"electricity_phase_three_consumed",
574+
"electricity_phase_one_produced",
575+
"electricity_phase_two_produced",
576+
"electricity_phase_three_produced",
561577
"electricity_produced",
562578
"electricity_produced_interval",
563579
"electricity_produced_off_peak_cumulative",
@@ -583,6 +599,9 @@
583599
"setpoint_low",
584600
"temperature_difference",
585601
"valve_position",
602+
"voltage_phase_one",
603+
"voltage_phase_two",
604+
"voltage_phase_three",
586605
"water_pressure",
587606
"water_temperature",
588607
)
@@ -662,6 +681,12 @@ class SmileSensors(TypedDict, total=False):
662681
electricity_consumed_peak_interval: int
663682
electricity_consumed_peak_point: int
664683
electricity_consumed_point: float
684+
electricity_phase_one_consumed: float
685+
electricity_phase_two_consumed: float
686+
electricity_phase_three_consumed: float
687+
electricity_phase_one_produced: float
688+
electricity_phase_two_produced: float
689+
electricity_phase_three_produced: float
665690
electricity_produced: float
666691
electricity_produced_interval: float
667692
electricity_produced_off_peak_cumulative: float
@@ -687,6 +712,9 @@ class SmileSensors(TypedDict, total=False):
687712
setpoint_high: float
688713
setpoint_low: float
689714
temperature_difference: float
715+
voltage_phase_one: float
716+
voltage_phase_two: float
717+
voltage_phase_three: float
690718
valve_position: float
691719
water_pressure: float
692720
water_temperature: float

plugwise/helper.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,11 @@ def power_data_energy_diff(
174174
measurement: str, net_string: str, f_val: float | int, direct_data: DeviceData
175175
) -> DeviceData:
176176
"""Calculate differential energy."""
177-
if "electricity" in measurement and "interval" not in net_string:
177+
if (
178+
"electricity" in measurement
179+
and "phase" not in measurement
180+
and "interval" not in net_string
181+
):
178182
diff = 1
179183
if "produced" in measurement:
180184
diff = -1
@@ -1141,6 +1145,8 @@ def _power_data_peak_value(self, direct_data: DeviceData, loc: Munch) -> Munch:
11411145
loc.key_string = f"{loc.measurement}_{log_found}"
11421146
if "gas" in loc.measurement:
11431147
loc.key_string = f"{loc.measurement}_{log_found}"
1148+
if "phase" in loc.measurement:
1149+
loc.key_string = f"{loc.measurement}"
11441150
loc.net_string = f"net_electricity_{log_found}"
11451151
val = loc.logs.find(loc.locator).text
11461152
loc.f_val = power_data_local_format(loc.attrs, loc.key_string, val)

plugwise/util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from .constants import (
1616
ARBITRARY_DATE,
17+
ELECTRIC_POTENTIAL_VOLT,
1718
ENERGY_KILO_WATT_HOUR,
1819
HW_MODELS,
1920
LOGADDR_OFFSET,
@@ -118,6 +119,8 @@ def format_measure(measure: str, unit: str) -> float | int | bool:
118119

119120
if unit in SPECIAL_FORMAT:
120121
result = float(f"{round(float_measure, 3):.3f}")
122+
elif unit == ELECTRIC_POTENTIAL_VOLT:
123+
result = float(f"{round(float_measure, 1):.1f}")
121124
else:
122125
if abs(float_measure) < 10:
123126
result = float(f"{round(float_measure, 2):.2f}")

tests/test_smile.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5067,6 +5067,141 @@ async def test_connect_p1v4(self):
50675067
await smile.close_connection()
50685068
await self.disconnect(server, client)
50695069

5070+
@pytest.mark.asyncio
5071+
async def test_connect_p1v4_440beta_single(self):
5072+
"""Test a P1 firmware 4 setup."""
5073+
testdata = {
5074+
"a455b61e52394b2db5081ce025a430f3": {
5075+
"dev_class": "gateway",
5076+
"firmware": "4.4.0",
5077+
"hardware": "AME Smile 2.0 board",
5078+
"location": "a455b61e52394b2db5081ce025a430f3",
5079+
"mac_address": "012345670001",
5080+
"model": "Gateway",
5081+
"name": "Smile P1",
5082+
"vendor": "Plugwise",
5083+
"binary_sensors": {"plugwise_notification": False},
5084+
},
5085+
"ba4de7613517478da82dd9b6abea36af": {
5086+
"dev_class": "smartmeter",
5087+
"location": "a455b61e52394b2db5081ce025a430f3",
5088+
"model": "KFM5KAIFA-METER",
5089+
"name": "P1",
5090+
"vendor": "SHENZHEN KAIFA TECHNOLOGY (CHENGDU) CO., LTD.",
5091+
"available": True,
5092+
"sensors": {
5093+
"net_electricity_point": 581,
5094+
"electricity_consumed_peak_point": 581,
5095+
"electricity_consumed_off_peak_point": 0,
5096+
"net_electricity_cumulative": 30718.064,
5097+
"electricity_consumed_peak_cumulative": 13523.584,
5098+
"electricity_consumed_off_peak_cumulative": 17194.48,
5099+
"electricity_consumed_peak_interval": 9,
5100+
"electricity_consumed_off_peak_interval": 0,
5101+
"electricity_produced_peak_point": 0,
5102+
"electricity_produced_off_peak_point": 0,
5103+
"electricity_produced_peak_cumulative": 0.0,
5104+
"electricity_produced_off_peak_cumulative": 0.0,
5105+
"electricity_produced_peak_interval": 0,
5106+
"electricity_produced_off_peak_interval": 0,
5107+
"electricity_phase_one_consumed": 0,
5108+
"electricity_phase_one_produced": 581,
5109+
},
5110+
},
5111+
}
5112+
5113+
self.smile_setup = "p1v4_440beta_single"
5114+
server, smile, client = await self.connect_wrapper()
5115+
assert smile.smile_hostname == "smile000000"
5116+
5117+
_LOGGER.info("Basics:")
5118+
_LOGGER.info(" # Assert type = power")
5119+
assert smile.smile_type == "power"
5120+
_LOGGER.info(" # Assert version")
5121+
assert smile.smile_version[0] == "4.4.0"
5122+
_LOGGER.info(" # Assert legacy")
5123+
assert not smile._smile_legacy
5124+
5125+
await self.device_test(smile, testdata)
5126+
assert smile.gateway_id == "a455b61e52394b2db5081ce025a430f3"
5127+
assert self.device_items == 31
5128+
assert not self.notifications
5129+
5130+
await smile.close_connection()
5131+
await self.disconnect(server, client)
5132+
5133+
@pytest.mark.asyncio
5134+
async def test_connect_p1v4_440beta_triple(self):
5135+
"""Test a P1 firmware 4 setup."""
5136+
testdata = {
5137+
"03e65b16e4b247a29ae0d75a78cb492e": {
5138+
"dev_class": "gateway",
5139+
"firmware": "4.4.0",
5140+
"hardware": "AME Smile 2.0 board",
5141+
"location": "03e65b16e4b247a29ae0d75a78cb492e",
5142+
"mac_address": "012345670001",
5143+
"model": "Gateway",
5144+
"name": "Smile P1",
5145+
"vendor": "Plugwise",
5146+
"binary_sensors": {"plugwise_notification": False},
5147+
},
5148+
"b82b6b3322484f2ea4e25e0bd5f3d61f": {
5149+
"dev_class": "smartmeter",
5150+
"location": "03e65b16e4b247a29ae0d75a78cb492e",
5151+
"model": "XMX5LGF0010453051839",
5152+
"name": "P1",
5153+
"vendor": "XEMEX NV",
5154+
"available": True,
5155+
"sensors": {
5156+
"net_electricity_point": 2422,
5157+
"electricity_consumed_peak_point": 2422,
5158+
"electricity_consumed_off_peak_point": 0,
5159+
"net_electricity_cumulative": 220806.738,
5160+
"electricity_consumed_peak_cumulative": 154585.221,
5161+
"electricity_consumed_off_peak_cumulative": 66221.517,
5162+
"electricity_consumed_peak_interval": 0,
5163+
"electricity_consumed_off_peak_interval": 0,
5164+
"electricity_produced_peak_point": 0,
5165+
"electricity_produced_off_peak_point": 0,
5166+
"electricity_produced_peak_cumulative": 0.0,
5167+
"electricity_produced_off_peak_cumulative": 0.0,
5168+
"electricity_produced_peak_interval": 0,
5169+
"electricity_produced_off_peak_interval": 0,
5170+
"electricity_phase_one_consumed": 0,
5171+
"electricity_phase_two_consumed": 0,
5172+
"electricity_phase_three_consumed": 0,
5173+
"electricity_phase_one_produced": 1737,
5174+
"electricity_phase_two_produced": 200,
5175+
"electricity_phase_three_produced": 486,
5176+
"gas_consumed_cumulative": 15263.4,
5177+
"gas_consumed_interval": 0.0,
5178+
"voltage_phase_one": 230.3,
5179+
"voltage_phase_two": 232.8,
5180+
"voltage_phase_three": 232.6,
5181+
},
5182+
},
5183+
}
5184+
5185+
self.smile_setup = "p1v4_440beta_triple"
5186+
server, smile, client = await self.connect_wrapper()
5187+
assert smile.smile_hostname == "smile000000"
5188+
5189+
_LOGGER.info("Basics:")
5190+
_LOGGER.info(" # Assert type = power")
5191+
assert smile.smile_type == "power"
5192+
_LOGGER.info(" # Assert version")
5193+
assert smile.smile_version[0] == "4.4.0"
5194+
_LOGGER.info(" # Assert legacy")
5195+
assert not smile._smile_legacy
5196+
5197+
await self.device_test(smile, testdata)
5198+
assert smile.gateway_id == "03e65b16e4b247a29ae0d75a78cb492e"
5199+
assert self.device_items == 40
5200+
assert not self.notifications
5201+
5202+
await smile.close_connection()
5203+
await self.disconnect(server, client)
5204+
50705205
@pytest.mark.asyncio
50715206
async def test_fail_legacy_system(self):
50725207
"""Test erroneous legacy stretch system."""

userdata/p1v4_440beta_single/core.domain_objects.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@
269269
<vendor_model>smile</vendor_model>
270270
<hardware_version>AME Smile 2.0 board</hardware_version>
271271
<firmware_version>4.4.0</firmware_version>
272-
<mac_address>C49300136E15</mac_address>
273-
<wifi_mac_address>C49300136E13</wifi_mac_address>
272+
<mac_address>012345670001</mac_address>
273+
<wifi_mac_address>012345670002</wifi_mac_address>
274274
<short_id>abcdefgh</short_id>
275275
<send_data>true</send_data>
276276
<anonymous>false</anonymous>

userdata/p1v4_440beta_triple/core.domain_objects.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@
112112
<vendor_model>smile</vendor_model>
113113
<hardware_version>AME Smile 2.0 board</hardware_version>
114114
<firmware_version>4.4.0</firmware_version>
115-
<mac_address>C49300137E71</mac_address>
116-
<wifi_mac_address>C49300137E6F</wifi_mac_address>
115+
<mac_address>012345670001</mac_address>
116+
<wifi_mac_address>012345670002</wifi_mac_address>
117117
<short_id>abcdefgh</short_id>
118118
<send_data>false</send_data>
119119
<anonymous>false</anonymous>

0 commit comments

Comments
 (0)