Skip to content

Commit 0ff4528

Browse files
authored
Merge pull request #95 from plugwise/support_p1_legacy_try_2
Fully support legacy P1
2 parents 46fe2aa + c6a2a3a commit 0ff4528

File tree

6 files changed

+61
-32
lines changed

6 files changed

+61
-32
lines changed

CHANGELOG.md

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

3+
## 0.13.0 - Smile: fully support P1 legacy (specifically with firmware v2.1.13)
4+
35
## 0.12.0 - Energy support and bugfixes
46

57
- Stick: Add new properties `energy_consumption_today` counter and `energy_consumption_today_last_reset` timestamp. These properties can be used to properly measure the used energy. Very useful for the 'Energy' capabilities introduced in Home Assistant 2021.8

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.12.0"
3+
__version__ = "0.13.0"
44

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

plugwise/helper.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def power_data_local_format(attrs, key_string, val):
201201

202202
def power_data_energy_diff(measurement, net_string, f_val, direct_data):
203203
"""Calculate differential energy."""
204-
if "electricity" in measurement:
204+
if "electricity" in measurement and "interval" not in net_string:
205205
diff = 1
206206
if "produced" in measurement:
207207
diff = -1
@@ -212,6 +212,7 @@ def power_data_energy_diff(measurement, net_string, f_val, direct_data):
212212
direct_data[net_string] += f_val * diff
213213
else:
214214
direct_data[net_string] += float(f_val * diff)
215+
direct_data[net_string] = float(f"{round(direct_data[net_string], 3):.3f}")
215216

216217
return direct_data
217218

@@ -392,6 +393,10 @@ def _all_locations(self):
392393
"members": loc.members,
393394
}
394395

396+
# Smile P1 has one valid location, skip any left-overs
397+
if self.smile_type == "power":
398+
return
399+
395400
return
396401

397402
def _get_module_data(self, appliance, locator, mod_type):
@@ -518,11 +523,13 @@ def _all_appliances(self):
518523
# Inject home_location as device id for legacy so
519524
# appl_data can use the location id as device id.
520525
self._appl_data[self._home_location] = {
521-
"name": "P1",
522-
"model": "Smile P1",
523-
"types": {"power", "home"},
524526
"class": "gateway",
527+
"fw": None,
525528
"location": self._home_location,
529+
"model": "Smile P1",
530+
"name": "P1",
531+
"types": {"power", "home"},
532+
"vendor": "Plugwise B.V.",
526533
}
527534
self.gateway_id = self._home_location
528535

@@ -736,6 +743,10 @@ def _get_appliance_data(self, d_id):
736743
Determined from APPLIANCES, for legacy from DOMAIN_OBJECTS.
737744
"""
738745
data = {}
746+
# P1 legacy has no APPLIANCES, also not present in DOMAIN_OBJECTS
747+
if self._smile_legacy and self.smile_type == "power":
748+
return data
749+
739750
search = self._appliances
740751
if self._smile_legacy and self.smile_type != "stretch":
741752
search = self._domain_objects
@@ -852,6 +863,10 @@ def _group_switches(self):
852863
Collect switching- or pump-group info.
853864
"""
854865
switch_groups = {}
866+
# P1 and Anna don't have switch groups
867+
if self.smile_type == "power" or self.smile_name == "Anna":
868+
return switch_groups
869+
855870
search = self._domain_objects
856871

857872
appliances = search.findall("./appliance")
@@ -914,7 +929,7 @@ def _power_data_peak_value(self, loc):
914929

915930
# Only once try to find P1 Legacy values
916931
if loc.logs.find(loc.locator) is None and self.smile_type == "power":
917-
# Skip peak if not split (P1 Legacy)
932+
# Skip peak if not split (P1 Legacy), this also results in one (peak_)point sensor for all P1's.
918933
if loc.peak_select == "nl_offpeak":
919934
loc.found = False
920935
return loc
@@ -952,8 +967,11 @@ def _power_data_from_location(self, loc_id):
952967

953968
search = self._domain_objects
954969
t_string = "tariff"
955-
if self._smile_legacy and self.smile_type == "power":
956-
t_string = "tariff_indicator"
970+
if self.smile_type == "power":
971+
# P1: use data from LOCATIONS
972+
search = self._locations
973+
if self._smile_legacy:
974+
t_string = "tariff_indicator"
957975

958976
loc.logs = search.find(f'.//location[@id="{loc_id}"]/logs')
959977

plugwise/smile.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,20 +204,23 @@ async def close_connection(self):
204204

205205
async def _full_update_device(self):
206206
"""Perform a first fetch of all XML data, needed for initialization."""
207-
await self._update_domain_objects()
208207
self._locations = await self._request(LOCATIONS)
208+
self._modules = await self._request(MODULES)
209209

210210
# P1 legacy has no appliances
211211
if not (self.smile_type == "power" and self._smile_legacy):
212212
self._appliances = await self._request(APPLIANCES)
213213

214-
# No need to import modules for P1, no userfull info
214+
# No need to import domain_objects and modules for P1, no useful info
215215
if self.smile_type != "power":
216-
self._modules = await self._request(MODULES)
216+
await self._update_domain_objects()
217217

218218
async def update_gw_devices(self):
219219
"""Perform an incremental update for updating the various device states."""
220-
await self._update_domain_objects()
220+
if self.smile_type != "power":
221+
await self._update_domain_objects()
222+
else:
223+
self._locations = await self._request(LOCATIONS)
221224

222225
# P1 legacy has no appliances
223226
if not (self.smile_type == "power" and self._smile_legacy):
@@ -342,9 +345,10 @@ def _device_data_anna(self, dev_id, details, device_data):
342345
device_data.pop("intended_boiler_state", None)
343346

344347
# Anna specific
345-
illuminance = self._object_value("appliance", dev_id, "illuminance")
346-
if illuminance is not None:
347-
device_data["illuminance"] = illuminance
348+
if self.smile_name == "Anna":
349+
illuminance = self._object_value("appliance", dev_id, "illuminance")
350+
if illuminance is not None:
351+
device_data["illuminance"] = illuminance
348352

349353
return device_data
350354

@@ -395,7 +399,10 @@ def _get_device_data(self, dev_id):
395399
# Generic
396400
if details["class"] == "gateway" or dev_id == self.gateway_id:
397401
# Anna: outdoor_temperature only present in domain_objects
398-
if "outdoor_temperature" not in device_data:
402+
if (
403+
self.smile_type == "thermostat"
404+
and "outdoor_temperature" not in device_data
405+
):
399406
outdoor_temperature = self._object_value(
400407
"location", self._home_location, "outdoor_temperature"
401408
)

tests/test_smile.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -751,14 +751,15 @@ async def test_connect_smile_p1_v2(self):
751751
# Gateway / P1 itself
752752
"938696c4bcdb4b8a9a595cb38ed43913": {
753753
"sensors": [
754-
{"id": "electricity_consumed_peak_point", "state": 458.0},
755-
{"id": "net_electricity_point", "state": 458.0},
756-
{"id": "gas_consumed_cumulative", "state": 584.433},
754+
{"id": "electricity_consumed_peak_point", "state": 456.0},
755+
{"id": "net_electricity_point", "state": 456.0},
756+
{"id": "gas_consumed_cumulative", "state": 584.431},
757757
{"id": "electricity_produced_peak_cumulative", "state": 1296.136},
758758
{
759759
"id": "electricity_produced_off_peak_cumulative",
760760
"state": 482.598,
761761
},
762+
{"id": "net_electricity_cumulative", "state": 1019.161},
762763
]
763764
}
764765
}
@@ -793,10 +794,10 @@ async def test_connect_smile_p1_v2_2(self):
793794
# Gateway / P1 itself
794795
"199aa40f126840f392983d171374ab0b": {
795796
"sensors": [
796-
{"id": "electricity_consumed_peak_point", "state": 368.0},
797-
{"id": "net_electricity_point", "state": 368.0},
798-
{"id": "gas_consumed_cumulative", "state": 2637.993},
799-
{"id": "electricity_produced_peak_cumulative", "state": 0.0},
797+
{"id": "electricity_consumed_peak_point", "state": 456.0},
798+
{"id": "net_electricity_point", "state": 456.0},
799+
{"id": "gas_consumed_cumulative", "state": 584.431},
800+
{"id": "electricity_produced_peak_cumulative", "state": 1296.136},
800801
]
801802
}
802803
}
@@ -1513,7 +1514,7 @@ async def test_connect_p1v3(self):
15131514
# Gateway / P1 itself
15141515
"ba4de7613517478da82dd9b6abea36af": {
15151516
"sensors": [
1516-
{"id": "electricity_consumed_peak_point", "state": 650.0},
1517+
{"id": "electricity_consumed_peak_point", "state": 636.0},
15171518
{"id": "electricity_produced_peak_cumulative", "state": 0.0},
15181519
{
15191520
"id": "electricity_consumed_off_peak_cumulative",
@@ -1523,6 +1524,7 @@ async def test_connect_p1v3(self):
15231524
"id": "electricity_consumed_peak_interval",
15241525
"state": [179, dt.datetime(2020, 3, 12, 19, 45)],
15251526
},
1527+
{"id": "net_electricity_cumulative", "state": 17965.326},
15261528
]
15271529
}
15281530
}
@@ -1554,13 +1556,13 @@ async def test_connect_p1v3solarfake(self):
15541556
# Gateway / P1 itself
15551557
"ba4de7613517478da82dd9b6abea36af": {
15561558
"sensors": [
1557-
{"id": "electricity_consumed_peak_point", "state": 644.0},
1559+
{"id": "electricity_consumed_peak_point", "state": 636.0},
15581560
{"id": "electricity_produced_peak_cumulative", "state": 20.0},
15591561
{
15601562
"id": "electricity_consumed_off_peak_cumulative",
15611563
"state": 10263.159,
15621564
},
1563-
{"id": "net_electricity_point", "state": 244},
1565+
{"id": "net_electricity_point", "state": 636},
15641566
]
15651567
}
15661568
}
@@ -1596,8 +1598,8 @@ async def test_connect_p1v3_full_option(self):
15961598
{"id": "electricity_consumed_peak_point", "state": 0.0},
15971599
{"id": "electricity_produced_peak_cumulative", "state": 396.559},
15981600
{"id": "electricity_consumed_off_peak_cumulative", "state": 551.09},
1599-
{"id": "electricity_produced_peak_point", "state": 2761},
1600-
{"id": "net_electricity_point", "state": -2761},
1601+
{"id": "electricity_produced_peak_point", "state": 2816},
1602+
{"id": "net_electricity_point", "state": -2816},
16011603
{"id": "gas_consumed_cumulative", "state": 584.85},
16021604
]
16031605
}
@@ -1855,7 +1857,7 @@ async def test_connect_p1v4(self):
18551857
# Gateway / P1 itself
18561858
"ba4de7613517478da82dd9b6abea36af": {
18571859
"sensors": [
1858-
{"id": "electricity_consumed_peak_point", "state": 571},
1860+
{"id": "electricity_consumed_peak_point", "state": 548},
18591861
{"id": "electricity_produced_peak_cumulative", "state": 0.0},
18601862
]
18611863
}

userdata/p1v3solarfake/core.locations.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
<unit>Wh</unit>
2929
<last_consecutive_log_date>2020-03-12T21:00:00+01:00</last_consecutive_log_date>
3030
<period start_date="2020-03-12T21:00:00+01:00" end_date="2020-03-12T21:00:00+01:00">
31-
<measurement log_date="2020-03-12T21:00:00+01:00" tariff="nl_peak">0.00</measurement>
32-
<measurement log_date="2020-03-12T21:00:00+01:00" tariff="nl_offpeak">0.00</measurement>
31+
<measurement log_date="2020-03-12T21:00:00+01:00" tariff="nl_peak">20000.00</measurement>
32+
<measurement log_date="2020-03-12T21:00:00+01:00" tariff="nl_offpeak">3000.00</measurement>
3333
</period>
3434
<electricity_cumulative_meter id='1fa5f5772e464e5cbcb595101adaf8e5'/>
3535
</cumulative_log>
@@ -62,7 +62,7 @@
6262
<interval>PT15M</interval>
6363
<period start_date="2020-03-12T20:45:00+01:00" end_date="2020-03-12T20:45:00+01:00" interval="PT15M">
6464
<measurement log_date="2020-03-12T20:45:00+01:00" tariff="nl_peak">0.00</measurement>
65-
<measurement log_date="2020-03-12T20:45:00+01:00" tariff="nl_offpeak">0.00</measurement>
65+
<measurement log_date="2020-03-12T20:45:00+01:00" tariff="nl_offpeak">20.00</measurement>
6666
</period>
6767
<electricity_interval_meter id='b3e07d45b7354d189cd0d5d41a4f80d7'/>
6868
</interval_log>

0 commit comments

Comments
 (0)