I have a energy meter which sends the kWh count periodically every few seconds via a serial port. To store this data I write the counter value and the calculated average power of the last 10s in a influxdb measurment.
To calculate the power i use a loop that compares the current counter value with the one 10s ago. To avoid that the loop is interrupted by reading the serial interface or sending the data via http i use serial_asyncio and aiohttp.
I am pretty new to Python and got my script running by doing serveral asyncio tutorials, so i am not sure if i mixed some old and new syntax.
The script is working, but I am not happy with a few things.
Is there a better way to pass the counter value from the serial data_received function to my calc_delta function without the use of global?
Am I using asyncio properly? I found different examples using asyncio.ensure_future() or loop.run_until_complete().
Is the overall structure okay, what could i have done better?
import aiohttp
import asyncio
from datetime import datetime
import serial_asyncio
import serial
import time
value = None
last_value = 0
token = "myInfluxdbToken"
class Input(asyncio.Protocol):
data_buffer = ""
def connection_made(self, transport):
self.transport = transport
print("port opened", transport)
def data_received(self, data):
global value
self.data_buffer += data.decode("utf-8")
# find counter value in received string
if "eHZ" in self.data_buffer:
data_tmp = self.data_buffer.replace("\r\n", "")
value_str = data_tmp.partition("1.8.1*255(")[2][:11]
if len(value_str) == 11:
value = float(value_str)
print(str(value))
asyncio.ensure_future(send_data(value, "counter"))
# Reset the data_buffer!
self.data_buffer = ""
async def calc_delta():
global value, last_value
# calculate counter delta
while True:
delta = 0
print(value)
if value:
delta = value - last_value
last_value = value
# 10s * 3600s/h * 1000W Calculates Avg Power of last 10s from kWh delta
deltaW = delta / 10 * 3600 * 1000
if deltaW < 50000:
await send_data(deltaW, "deltaW")
print(time.perf_counter(), deltaW)
else:
print(time.perf_counter(), "data invalid")
await asyncio.sleep(10)
async def send_data(data, tag):
async with aiohttp.ClientSession() as session:
async with session.post(
"http://localhost:8086/api/v2/write?org=my_org&bucket=testdata&precision=s",
data=f"ehzdata,type={tag} value={data}",
headers={"Authorization": f"Token {token}"},
) as response:
print("Status:", response.status)
loop = asyncio.get_event_loop()
serial_coro = serial_asyncio.create_serial_connection(
loop, Input, "/dev/ttyUSB0", baudrate=9600, parity=serial.PARITY_EVEN, bytesize=7
)
counter_coro = calc_delta()
asyncio.ensure_future(serial_coro)
loop.run_until_complete(counter_coro)
loop.run_forever()
loop.close()