juham-automation 0.0.4__py3-none-any.whl → 0.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,139 +1,139 @@
1
- import json
2
- from typing import Any, Dict, cast
3
- from typing_extensions import override
4
-
5
- from masterpiece.mqtt import MqttMsg
6
- from juham_core import Juham
7
- from juham_core.timeutils import timestamp
8
- from juham_core import MasterPieceThread, JuhamThread
9
-
10
-
11
- class PowerMeterSimulatorThread(MasterPieceThread):
12
- """Thread simulating Energy Meter."""
13
-
14
- _power: float = 1000.0 # W
15
- _power_topic: str = "power"
16
- _interval: float = 10 # 10 seconds
17
-
18
- def __init__(self) -> None:
19
- """Construct a thread for publishing power data.
20
-
21
- Args:
22
- topic (str, optional): MQTT topic to post the sensor readings. Defaults to None.
23
- interval (float, optional): Interval specifying how often the sensor is read. Defaults to 60 seconds.
24
- """
25
- super().__init__(None)
26
- self.current_ts: float = timestamp()
27
-
28
- @classmethod
29
- def initialize(cls, power_topic: str, power: float, interval: float) -> None:
30
- """Initialize thread class attributes.
31
-
32
- Args:
33
- power_topic (str): topic to publish the energy meter readings
34
- power (float): power to be simulated, the default is 1kW
35
- interval (float): update interval, the default is 10s
36
- """
37
- cls._power = power
38
- cls._interval = interval
39
- cls._power_topic = power_topic
40
-
41
- @override
42
- def update_interval(self) -> float:
43
- return self._interval
44
-
45
- def publish_active_power(self, ts: float) -> None:
46
- """Publish the active power, also known as real power. This is that
47
- part of the power that can be converted to useful work.
48
-
49
- Args:
50
- ts (str): time stamp of the event
51
-
52
- """
53
- dt = ts - self.current_ts
54
- self.current_ts = ts
55
-
56
- msg = {
57
- "timestamp": ts,
58
- "real_a": self._power * dt,
59
- "real_b": self._power * dt,
60
- "real_c": self._power * dt,
61
- "real_total": 3 * self._power * dt,
62
- }
63
- self.publish(self._power_topic, json.dumps(msg), 1, True)
64
-
65
- @override
66
- def update(self) -> bool:
67
- super().update()
68
- self.publish_active_power(timestamp())
69
- return True
70
-
71
-
72
- class PowerMeterSimulator(JuhamThread):
73
- """Simulator energy meter sensor. Spawns a thread
74
- to simulate Shelly PM mqtt messages"""
75
-
76
- workerThreadId = PowerMeterSimulatorThread.get_class_id()
77
- update_interval: float = 10
78
- power: float = 1000.0
79
-
80
- _POWERMETERSIMULATOR: str = "_powermetersimulator"
81
-
82
- def __init__(
83
- self,
84
- name: str = "em",
85
- interval: float = 0,
86
- ) -> None:
87
- """Create energy meter simulator.
88
-
89
- Args:
90
- name (str, optional): Name of the object. Defaults to 'em'.
91
- topic (str, optional): MQTT topic to publish the energy meter reports. Defaults to None.
92
- interval (float, optional): interval between events, in seconds. Defaults to None.
93
- """
94
- super().__init__(name)
95
- self.update_ts: float = 0.0
96
- if interval > 0.0:
97
- self.update_interval = interval
98
- self.power_topic = self.make_topic_name("powerconsumption") # target topic
99
-
100
- @override
101
- def on_message(self, client: object, userdata: Any, msg: MqttMsg) -> None:
102
- if msg.topic == self.power_topic:
103
- em = json.loads(msg.payload.decode())
104
- self.on_sensor(em)
105
- else:
106
- super().on_message(client, userdata, msg)
107
-
108
- def on_sensor(self, em: dict[Any, Any]) -> None:
109
- """Handle data coming from the energy meter.
110
-
111
- Simply log the event to indicate the presense of simulated device.
112
- Args:
113
- em (dict): data from the sensor
114
- """
115
- self.debug(f"Simulated power meter sensor {em}")
116
-
117
- @override
118
- def run(self) -> None:
119
- PowerMeterSimulatorThread.initialize(
120
- self.power_topic, self.power, self.update_interval
121
- )
122
- self.worker = cast(
123
- PowerMeterSimulatorThread,
124
- Juham.instantiate(PowerMeterSimulatorThread.get_class_id()),
125
- )
126
- super().run()
127
-
128
- @override
129
- def to_dict(self) -> Dict[str, Any]:
130
- data: Dict[str, Any] = super().to_dict()
131
- data[self._POWERMETERSIMULATOR] = {"power_topic": self.power_topic}
132
- return data
133
-
134
- @override
135
- def from_dict(self, data: Dict[str, Any]) -> None:
136
- super().from_dict(data)
137
- if self._POWERMETERSIMULATOR in data:
138
- for key, value in data[self._POWERMETERSIMULATOR].items():
139
- setattr(self, key, value)
1
+ import json
2
+ from typing import Any, Dict, cast
3
+ from typing_extensions import override
4
+
5
+ from masterpiece.mqtt import MqttMsg
6
+ from juham_core import Juham
7
+ from juham_core.timeutils import timestamp
8
+ from juham_core import MasterPieceThread, JuhamThread
9
+
10
+
11
+ class PowerMeterSimulatorThread(MasterPieceThread):
12
+ """Thread simulating Energy Meter."""
13
+
14
+ _power: float = 1000.0 # W
15
+ _power_topic: str = "power"
16
+ _interval: float = 10 # 10 seconds
17
+
18
+ def __init__(self) -> None:
19
+ """Construct a thread for publishing power data.
20
+
21
+ Args:
22
+ topic (str, optional): MQTT topic to post the sensor readings. Defaults to None.
23
+ interval (float, optional): Interval specifying how often the sensor is read. Defaults to 60 seconds.
24
+ """
25
+ super().__init__(None)
26
+ self.current_ts: float = timestamp()
27
+
28
+ @classmethod
29
+ def initialize(cls, power_topic: str, power: float, interval: float) -> None:
30
+ """Initialize thread class attributes.
31
+
32
+ Args:
33
+ power_topic (str): topic to publish the energy meter readings
34
+ power (float): power to be simulated, the default is 1kW
35
+ interval (float): update interval, the default is 10s
36
+ """
37
+ cls._power = power
38
+ cls._interval = interval
39
+ cls._power_topic = power_topic
40
+
41
+ @override
42
+ def update_interval(self) -> float:
43
+ return self._interval
44
+
45
+ def publish_active_power(self, ts: float) -> None:
46
+ """Publish the active power, also known as real power. This is that
47
+ part of the power that can be converted to useful work.
48
+
49
+ Args:
50
+ ts (str): time stamp of the event
51
+
52
+ """
53
+ dt = ts - self.current_ts
54
+ self.current_ts = ts
55
+
56
+ msg = {
57
+ "timestamp": ts,
58
+ "real_a": self._power * dt,
59
+ "real_b": self._power * dt,
60
+ "real_c": self._power * dt,
61
+ "real_total": 3 * self._power * dt,
62
+ }
63
+ self.publish(self._power_topic, json.dumps(msg), 1, True)
64
+
65
+ @override
66
+ def update(self) -> bool:
67
+ super().update()
68
+ self.publish_active_power(timestamp())
69
+ return True
70
+
71
+
72
+ class PowerMeterSimulator(JuhamThread):
73
+ """Simulator energy meter sensor. Spawns a thread
74
+ to simulate Shelly PM mqtt messages"""
75
+
76
+ workerThreadId = PowerMeterSimulatorThread.get_class_id()
77
+ update_interval: float = 10
78
+ power: float = 1000.0
79
+
80
+ _POWERMETERSIMULATOR: str = "_powermetersimulator"
81
+
82
+ def __init__(
83
+ self,
84
+ name: str = "em",
85
+ interval: float = 0,
86
+ ) -> None:
87
+ """Create energy meter simulator.
88
+
89
+ Args:
90
+ name (str, optional): Name of the object. Defaults to 'em'.
91
+ topic (str, optional): MQTT topic to publish the energy meter reports. Defaults to None.
92
+ interval (float, optional): interval between events, in seconds. Defaults to None.
93
+ """
94
+ super().__init__(name)
95
+ self.update_ts: float = 0.0
96
+ if interval > 0.0:
97
+ self.update_interval = interval
98
+ self.power_topic = self.make_topic_name("powerconsumption") # target topic
99
+
100
+ @override
101
+ def on_message(self, client: object, userdata: Any, msg: MqttMsg) -> None:
102
+ if msg.topic == self.power_topic:
103
+ em = json.loads(msg.payload.decode())
104
+ self.on_sensor(em)
105
+ else:
106
+ super().on_message(client, userdata, msg)
107
+
108
+ def on_sensor(self, em: dict[Any, Any]) -> None:
109
+ """Handle data coming from the energy meter.
110
+
111
+ Simply log the event to indicate the presense of simulated device.
112
+ Args:
113
+ em (dict): data from the sensor
114
+ """
115
+ self.debug(f"Simulated power meter sensor {em}")
116
+
117
+ @override
118
+ def run(self) -> None:
119
+ PowerMeterSimulatorThread.initialize(
120
+ self.power_topic, self.power, self.update_interval
121
+ )
122
+ self.worker = cast(
123
+ PowerMeterSimulatorThread,
124
+ Juham.instantiate(PowerMeterSimulatorThread.get_class_id()),
125
+ )
126
+ super().run()
127
+
128
+ @override
129
+ def to_dict(self) -> Dict[str, Any]:
130
+ data: Dict[str, Any] = super().to_dict()
131
+ data[self._POWERMETERSIMULATOR] = {"power_topic": self.power_topic}
132
+ return data
133
+
134
+ @override
135
+ def from_dict(self, data: Dict[str, Any]) -> None:
136
+ super().from_dict(data)
137
+ if self._POWERMETERSIMULATOR in data:
138
+ for key, value in data[self._POWERMETERSIMULATOR].items():
139
+ setattr(self, key, value)
@@ -1,123 +1,123 @@
1
- from datetime import datetime
2
- import time
3
- import json
4
- from typing import Any, Dict, Optional, cast
5
- from typing_extensions import override
6
-
7
- from masterpiece.mqtt import Mqtt, MqttMsg
8
- from juham_core import JuhamCloudThread, JuhamThread
9
-
10
-
11
- class SpotHintaFiThread(JuhamCloudThread):
12
- """Thread running SpotHinta.fi.
13
-
14
- Periodically fetches the spot electricity prices and publishes them
15
- to 'spot' topic.
16
- """
17
-
18
- _spot_topic: str = ""
19
- _url: str = ""
20
- _interval: float = 12 * 3600
21
-
22
- def __init__(self, client: Optional[Mqtt] = None) -> None:
23
- super().__init__(client)
24
- self._interval = 60
25
-
26
- def init(self, topic: str, url: str, interval: float) -> None:
27
- self._spot_topic = topic
28
- self._url = url
29
- self._interval = interval
30
-
31
- @override
32
- def make_weburl(self) -> str:
33
- return self._url
34
-
35
- @override
36
- def update_interval(self) -> float:
37
- return self._interval
38
-
39
- @override
40
- def process_data(self, rawdata: Any) -> None:
41
- """Publish electricity price message to Juham topic.
42
-
43
- Args:
44
- rawdata (dict): electricity prices
45
- """
46
-
47
- super().process_data(rawdata)
48
- data = rawdata.json()
49
-
50
- spot = []
51
- for e in data:
52
- ts = time.mktime(time.strptime(e["DateTime"], "%Y-%m-%dT%H:%M:%S%z"))
53
- hour = datetime.utcfromtimestamp(ts).strftime("%H")
54
- h = {
55
- "Timestamp": ts,
56
- "hour": hour,
57
- "Rank": e["Rank"],
58
- "PriceWithTax": e["PriceWithTax"],
59
- }
60
- spot.append(h)
61
- self.publish(self._spot_topic, json.dumps(spot), 1, True)
62
- self.info(f"Spot electricity prices published for the next {len(spot)} days")
63
-
64
-
65
- class SpotHintaFi(JuhamThread):
66
- """Spot electricity price for reading hourly electricity prices from
67
- https://api.spot-hinta.fi site.
68
- """
69
-
70
- worker_thread_id = SpotHintaFiThread.get_class_id()
71
- url = "https://api.spot-hinta.fi/TodayAndDayForward"
72
- update_interval = 12 * 3600
73
-
74
- def __init__(self, name: str = "rspothintafi") -> None:
75
- super().__init__(name)
76
- self.active_liter_lpm = -1
77
- self.update_ts = None
78
- self.spot_topic = self.make_topic_name("spot")
79
-
80
- @override
81
- def on_connect(self, client: object, userdata: Any, flags: int, rc: int) -> None:
82
- super().on_connect(client, userdata, flags, rc)
83
- if rc == 0:
84
- self.subscribe(self.spot_topic)
85
-
86
- @override
87
- def on_message(self, client: object, userdata: Any, msg: MqttMsg) -> None:
88
- if msg.topic == self.spot_topic:
89
- em = json.loads(msg.payload.decode())
90
- self.on_spot(em)
91
- else:
92
- super().on_message(client, userdata, msg)
93
-
94
- def on_spot(self, m: dict[Any, Any]) -> None:
95
- """Write hourly spot electricity prices to time series database.
96
-
97
- Args:
98
- m (dict): holding hourly spot electricity prices
99
- """
100
- pass
101
-
102
- @override
103
- def run(self) -> None:
104
- self.worker = cast(SpotHintaFiThread, self.instantiate(self.worker_thread_id))
105
- self.worker.init(self.spot_topic, self.url, self.update_interval)
106
- super().run()
107
-
108
- @override
109
- def to_dict(self) -> Dict[str, Any]:
110
- data: Dict[str, Any] = super().to_dict()
111
- data["_spothintafi"] = {
112
- "topic": self.spot_topic,
113
- "url": self.url,
114
- "interval": self.update_interval,
115
- }
116
- return data
117
-
118
- @override
119
- def from_dict(self, data: Dict[str, Any]) -> None:
120
- super().from_dict(data)
121
- if "_spothintafi" in data:
122
- for key, value in data["_spothintafi"].items():
123
- setattr(self, key, value)
1
+ from datetime import datetime
2
+ import time
3
+ import json
4
+ from typing import Any, Dict, Optional, cast
5
+ from typing_extensions import override
6
+
7
+ from masterpiece.mqtt import Mqtt, MqttMsg
8
+ from juham_core import JuhamCloudThread, JuhamThread
9
+
10
+
11
+ class SpotHintaFiThread(JuhamCloudThread):
12
+ """Thread running SpotHinta.fi.
13
+
14
+ Periodically fetches the spot electricity prices and publishes them
15
+ to 'spot' topic.
16
+ """
17
+
18
+ _spot_topic: str = ""
19
+ _url: str = ""
20
+ _interval: float = 12 * 3600
21
+
22
+ def __init__(self, client: Optional[Mqtt] = None) -> None:
23
+ super().__init__(client)
24
+ self._interval = 60
25
+
26
+ def init(self, topic: str, url: str, interval: float) -> None:
27
+ self._spot_topic = topic
28
+ self._url = url
29
+ self._interval = interval
30
+
31
+ @override
32
+ def make_weburl(self) -> str:
33
+ return self._url
34
+
35
+ @override
36
+ def update_interval(self) -> float:
37
+ return self._interval
38
+
39
+ @override
40
+ def process_data(self, rawdata: Any) -> None:
41
+ """Publish electricity price message to Juham topic.
42
+
43
+ Args:
44
+ rawdata (dict): electricity prices
45
+ """
46
+
47
+ super().process_data(rawdata)
48
+ data = rawdata.json()
49
+
50
+ spot = []
51
+ for e in data:
52
+ ts = time.mktime(time.strptime(e["DateTime"], "%Y-%m-%dT%H:%M:%S%z"))
53
+ hour = datetime.utcfromtimestamp(ts).strftime("%H")
54
+ h = {
55
+ "Timestamp": ts,
56
+ "hour": hour,
57
+ "Rank": e["Rank"],
58
+ "PriceWithTax": e["PriceWithTax"],
59
+ }
60
+ spot.append(h)
61
+ self.publish(self._spot_topic, json.dumps(spot), 1, True)
62
+ self.info(f"Spot electricity prices published for the next {len(spot)} days")
63
+
64
+
65
+ class SpotHintaFi(JuhamThread):
66
+ """Spot electricity price for reading hourly electricity prices from
67
+ https://api.spot-hinta.fi site.
68
+ """
69
+
70
+ worker_thread_id = SpotHintaFiThread.get_class_id()
71
+ url = "https://api.spot-hinta.fi/TodayAndDayForward"
72
+ update_interval = 12 * 3600
73
+
74
+ def __init__(self, name: str = "rspothintafi") -> None:
75
+ super().__init__(name)
76
+ self.active_liter_lpm = -1
77
+ self.update_ts = None
78
+ self.spot_topic = self.make_topic_name("spot")
79
+
80
+ @override
81
+ def on_connect(self, client: object, userdata: Any, flags: int, rc: int) -> None:
82
+ super().on_connect(client, userdata, flags, rc)
83
+ if rc == 0:
84
+ self.subscribe(self.spot_topic)
85
+
86
+ @override
87
+ def on_message(self, client: object, userdata: Any, msg: MqttMsg) -> None:
88
+ if msg.topic == self.spot_topic:
89
+ em = json.loads(msg.payload.decode())
90
+ self.on_spot(em)
91
+ else:
92
+ super().on_message(client, userdata, msg)
93
+
94
+ def on_spot(self, m: dict[Any, Any]) -> None:
95
+ """Write hourly spot electricity prices to time series database.
96
+
97
+ Args:
98
+ m (dict): holding hourly spot electricity prices
99
+ """
100
+ pass
101
+
102
+ @override
103
+ def run(self) -> None:
104
+ self.worker = cast(SpotHintaFiThread, self.instantiate(self.worker_thread_id))
105
+ self.worker.init(self.spot_topic, self.url, self.update_interval)
106
+ super().run()
107
+
108
+ @override
109
+ def to_dict(self) -> Dict[str, Any]:
110
+ data: Dict[str, Any] = super().to_dict()
111
+ data["_spothintafi"] = {
112
+ "topic": self.spot_topic,
113
+ "url": self.url,
114
+ "interval": self.update_interval,
115
+ }
116
+ return data
117
+
118
+ @override
119
+ def from_dict(self, data: Dict[str, Any]) -> None:
120
+ super().from_dict(data)
121
+ if "_spothintafi" in data:
122
+ for key, value in data["_spothintafi"].items():
123
+ setattr(self, key, value)