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.

  1. 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?

  2. Am I using asyncio properly? I found different examples using asyncio.ensure_future() or loop.run_until_complete().

  3. 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)
                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
        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)
            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(
            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()


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.