Skip to content

Commit 334aac6

Browse files
committed
Use Neoom Beaam to measure sun irradiation
1 parent 05a8210 commit 334aac6

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

Beaam.env.template

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
MQTT_SERVER = localhost
2+
MQTT_USER = beaam
3+
MQTT_PASSWORD = ...
4+
MQTT_TOPIC = beaam/status/power_produced/average_smooth
5+
6+
BEAAM_API_STATE_URL = http://beaam/api/v1/site/state
7+
BEAAM_API_TOKEN = sk_beaam_...

energy-monitor-beaam.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright 2025 Oliver Heimlich <[email protected]>
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
"""Periodically poll the Neoom Beaam API and publish the power level of
19+
PV production via MQTT
20+
21+
@author: Oliver Heimlich <[email protected]>
22+
"""
23+
24+
import logging
25+
import dotenv
26+
import timeloop
27+
import json
28+
import datetime
29+
import asyncio
30+
import requests
31+
32+
from modules import mqttclient
33+
34+
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
35+
level=logging.INFO)
36+
37+
config = dotenv.dotenv_values("Beaam.env")
38+
39+
background = timeloop.Timeloop()
40+
41+
def find_value_by_key(data, target_key):
42+
for item in data:
43+
if item['key'] == target_key:
44+
return item['value']
45+
return None
46+
47+
def get_energy_flow_states():
48+
global config
49+
50+
headers = {
51+
'Authorization': 'Bearer ' + config['BEAAM_API_TOKEN']
52+
}
53+
response = requests.get(config['BEAAM_API_STATE_URL'], headers=headers)
54+
response.raise_for_status()
55+
data = response.json()
56+
return data['energyFlow']['states']
57+
58+
average_power = 0.0
59+
@background.job(interval = datetime.timedelta(minutes = 1))
60+
def update_measurement():
61+
global average_power
62+
global config
63+
64+
current_power_production = find_value_by_key(
65+
get_energy_flow_states(),
66+
'POWER_PRODUCTION')
67+
68+
smoothing_factor = 0.125
69+
average_power += smoothing_factor * (current_power_production - average_power)
70+
mqttclient.publish(config['MQTT_TOPIC'], "%d" % (average_power))
71+
72+
loop = None
73+
async def main():
74+
global config
75+
global loop
76+
77+
loop = asyncio.get_running_loop()
78+
79+
mqttclient.connect(server=config['MQTT_SERVER'], user=config['MQTT_USER'], password=config['MQTT_PASSWORD'])
80+
81+
background.start()
82+
83+
try:
84+
while True:
85+
await asyncio.sleep(60)
86+
finally:
87+
background.stop()
88+
mqttclient.disconnect()
89+
90+
asyncio.run(main())

modules/mqttclient.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
# Send commands to shelly devices over MQTT
88
# see https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/Mqtt/#mqtt-control
99

10-
def shelly_command(topic_prefix, component_id, command):
10+
def publish(topic, message):
1111
global client
12+
client.publish(topic, message, qos=1)
13+
1214

15+
def shelly_command(topic_prefix, component_id, command):
1316
topic = "%s/command/%s" % (topic_prefix, component_id)
14-
client.publish(topic, command, qos=1)
17+
publish(topic, command)
1518

1619

1720
client = None

0 commit comments

Comments
 (0)