Testing Docker file
This commit is contained in:
parent
f1e62f5344
commit
7f66e99cfa
11
Dockerfile
11
Dockerfile
|
|
@ -2,10 +2,15 @@
|
||||||
|
|
||||||
FROM python:3.10-slim-buster
|
FROM python:3.10-slim-buster
|
||||||
|
|
||||||
|
RUN mkdir /app
|
||||||
|
COPY . /app
|
||||||
|
COPY pyproject.toml /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENV PYTHONPATH=${PYTHONPATH}:${PWD}
|
||||||
|
RUN pip3 install poetry
|
||||||
|
RUN poetry config virtualenvs.create false
|
||||||
|
RUN poetry install --only main
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt requirements.txt
|
|
||||||
RUN pip3 install -r requirements.txt
|
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,12 @@ services:
|
||||||
container_name: huawei-solar
|
container_name: huawei-solar
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
image: huawei-solar-rtu:latest
|
image: huawei-solar-rtu:latest
|
||||||
user: root
|
|
||||||
devices:
|
|
||||||
- /dev/ttyUSB0:/dev/ttyUSB0
|
|
||||||
environment:
|
environment:
|
||||||
- INVERTER_PORT=/dev/ttyUSB0
|
- INVERTER_HOST=192.168.200.100
|
||||||
- MQTT_HOST=192.168.43.102
|
- MQTT_HOST=192.168.1.100
|
||||||
- BROKER_PORT=1883
|
- USE_CREDENTIALS=YES
|
||||||
- USE_CREDENTIALS=NO
|
- USER_NAME=simon
|
||||||
- USER_NAME=none
|
- PASSWORD=bajsa123
|
||||||
- PASSWORD=none
|
- LOGLEVEL=DEBUG
|
||||||
- MQTT_TOPIC=raspberryTopic
|
- MQTT_TOPIC=raspberryTopic
|
||||||
- DATA_MODE=INVERTER # INVERTER or OFFLINE
|
- DATA_MODE=INVERTER # INVERTER or OFFLINE
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ authors = ["Simon Milvert <simon@milvert.com>"]
|
||||||
python = "^3.9"
|
python = "^3.9"
|
||||||
huawei-solar = "^2.2.4"
|
huawei-solar = "^2.2.4"
|
||||||
paho-mqtt = "^1.6.1"
|
paho-mqtt = "^1.6.1"
|
||||||
|
python-dotenv = "^1.0.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^7.2.1"
|
pytest = "^7.2.1"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
FORMAT = (
|
||||||
|
"%(asctime)-15s %(threadName)-15s "
|
||||||
|
"%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
LOGLEVEL = os.environ.get("LOGLEVEL", "INFO").upper()
|
||||||
|
logging.basicConfig(level=LOGLEVEL, format=FORMAT)
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
from src.data import InverterData
|
from src.data import InverterData
|
||||||
from src.log import log_info
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def get_data(client, register, slave_id):
|
async def get_data(client, register, slave_id):
|
||||||
result = await client.get(register, slave_id)
|
result = await client.get(register, slave_id)
|
||||||
log_info(f"{register}: {result.value}")
|
LOGGER.debug(f"{register}: {result.value}")
|
||||||
return InverterData(value=result.value, unit=result.unit, name=register)
|
return InverterData(value=result.value, unit=result.unit, name=register)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from src.data import InverterData, ReadRegister
|
from src.data import InverterData, ReadRegister
|
||||||
from src.log import log_info
|
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
POSSIBLE_SAMPLE_UNITS = [
|
POSSIBLE_SAMPLE_UNITS = [
|
||||||
"EXAMPLE_UNIT_A",
|
"EXAMPLE_UNIT_A",
|
||||||
"EXAMPLE_UNIT_B",
|
"EXAMPLE_UNIT_B",
|
||||||
|
|
@ -14,7 +15,7 @@ POSSIBLE_SAMPLE_UNITS = [
|
||||||
|
|
||||||
|
|
||||||
async def get_dummy_data() -> InverterData:
|
async def get_dummy_data() -> InverterData:
|
||||||
log_info("Generate dummy data")
|
LOGGER.info("Generate dummy data")
|
||||||
value = random.randint(0, 100)
|
value = random.randint(0, 100)
|
||||||
name = random.choice(ReadRegister.reg_to_read_measured)
|
name = random.choice(ReadRegister.reg_to_read_measured)
|
||||||
unit = random.choice(POSSIBLE_SAMPLE_UNITS)
|
unit = random.choice(POSSIBLE_SAMPLE_UNITS)
|
||||||
|
|
|
||||||
13
src/log.py
13
src/log.py
|
|
@ -1,13 +0,0 @@
|
||||||
import logging
|
|
||||||
|
|
||||||
FORMAT = (
|
|
||||||
"%(asctime)-15s %(threadName)-15s "
|
|
||||||
"%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s"
|
|
||||||
)
|
|
||||||
logging.basicConfig(format=FORMAT)
|
|
||||||
log = logging.getLogger()
|
|
||||||
log.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
def log_info(message):
|
|
||||||
log.info(message)
|
|
||||||
83
src/main.py
83
src/main.py
|
|
@ -1,59 +1,63 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import paho.mqtt.client
|
||||||
from huawei_solar import AsyncHuaweiSolar
|
from huawei_solar import AsyncHuaweiSolar
|
||||||
from huawei_solar import register_values as rv
|
from huawei_solar import register_values as rv
|
||||||
|
|
||||||
|
from src import mqtt
|
||||||
from src.data import InverterData, ReadRegister
|
from src.data import InverterData, ReadRegister
|
||||||
from src.inverter import get_data
|
from src.inverter import get_data
|
||||||
from src.inverter_dummy import get_dummy_data
|
from src.inverter_dummy import get_dummy_data
|
||||||
from src.log import log_info
|
|
||||||
from src.mqtt import connect
|
from src.mqtt import connect
|
||||||
|
|
||||||
DATA_MODE = os.getenv("DATA_MODE", "dummy")
|
DATA_MODE = os.getenv("DATA_MODE", "INVERTER")
|
||||||
MQTT_TOPIC = os.getenv("MQTT_TOPIC", "inverter")
|
MQTT_TOPIC = os.getenv("MQTT_TOPIC", "inverter")
|
||||||
|
FORCE_GET = os.getenv("FORCE_GET", False)
|
||||||
|
|
||||||
|
|
||||||
REQUEST_INTERVAL = 60
|
|
||||||
slave_id = os.getenv("INVERTER_ID", 1)
|
slave_id = os.getenv("INVERTER_ID", 1)
|
||||||
port = os.getenv("INVERTER_PORT", 502)
|
port = os.getenv("INVERTER_PORT", 502)
|
||||||
host = os.getenv("INVERTER_HOST", "10.0.2.20")
|
host = os.getenv("INVERTER_HOST", "192.168.200.100")
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
REQUEST_INTERVAL = 60
|
||||||
|
|
||||||
|
|
||||||
async def get_inverter_client() -> (InverterData, str):
|
async def get_inverter_client() -> AsyncHuaweiSolar:
|
||||||
inverter_client = await AsyncHuaweiSolar.create(host, port, slave_id)
|
inverter_client = await AsyncHuaweiSolar.create(host, port, slave_id)
|
||||||
log_info("-- INVERTER -- Connected to Inverter")
|
LOGGER.info("-- INVERTER -- Connected to Inverter")
|
||||||
|
return inverter_client
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
inverter_client = await get_inverter_client()
|
||||||
|
count = 0
|
||||||
|
while True:
|
||||||
status = await inverter_client.get(
|
status = await inverter_client.get(
|
||||||
ReadRegister.inverter_reg_status, slave_id
|
ReadRegister.inverter_reg_status, slave_id
|
||||||
)
|
)
|
||||||
|
|
||||||
log_info(f"-- INVERTER -- Status: {status}")
|
LOGGER.info(f"-- INVERTER -- Status: {status}")
|
||||||
return inverter_client, status
|
|
||||||
|
|
||||||
|
if (
|
||||||
async def main():
|
status.value == rv.DEVICE_STATUS_DEFINITIONS.get(0x0200)
|
||||||
inverter_client, status = await get_inverter_client()
|
or FORCE_GET
|
||||||
count = 0
|
|
||||||
while True:
|
|
||||||
if status.value == rv.DEVICE_STATUS_DEFINITIONS.get(
|
|
||||||
0x0200
|
|
||||||
): # Inverter is active, Get data
|
): # Inverter is active, Get data
|
||||||
# Get measured values
|
LOGGER.info("-- INVERTER -- Send measured values")
|
||||||
for register in ReadRegister.reg_to_read_measured:
|
for register in ReadRegister.reg_to_read_measured:
|
||||||
result = await get_inverter_data(
|
result = await get_inverter_data(inverter_client, register)
|
||||||
inverter_client, register, slave_id
|
|
||||||
)
|
|
||||||
send_data(
|
send_data(
|
||||||
mqtt_client,
|
mqtt_client,
|
||||||
format_data_to_serialized_json(result),
|
format_data_to_serialized_json(result),
|
||||||
f"measure/{result.name}",
|
f"measure/{result.name}",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get calculated values
|
LOGGER.info("-- INVERTER -- Send calculated values")
|
||||||
for register in ReadRegister.reg_to_read_calculated:
|
for register in ReadRegister.reg_to_read_calculated:
|
||||||
result = await get_inverter_data(
|
result = await get_inverter_data(inverter_client, register)
|
||||||
inverter_client, register, slave_id
|
|
||||||
)
|
|
||||||
send_data(
|
send_data(
|
||||||
mqtt_client,
|
mqtt_client,
|
||||||
format_data_to_serialized_json(result),
|
format_data_to_serialized_json(result),
|
||||||
|
|
@ -61,23 +65,29 @@ async def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
if count == 5:
|
if count == 5:
|
||||||
|
LOGGER.info("-- INVERTER -- Send status/alarm")
|
||||||
for register in ReadRegister.reg_to_read_status:
|
for register in ReadRegister.reg_to_read_status:
|
||||||
result = await get_inverter_data(
|
result = await get_inverter_data(inverter_client, register)
|
||||||
inverter_client, register, slave_id
|
|
||||||
)
|
|
||||||
send_data(
|
send_data(
|
||||||
mqtt_client,
|
mqtt_client,
|
||||||
format_data_to_serialized_json(result),
|
format_data_to_serialized_json(result),
|
||||||
f"status/{result.name}",
|
f"status/{result.name}",
|
||||||
)
|
)
|
||||||
count = 0
|
count = 0
|
||||||
|
else:
|
||||||
|
LOGGER.debug("-- INVERTER -- Not Active, No need to read values")
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
LOGGER.info(f"Sleeping {REQUEST_INTERVAL}")
|
||||||
await asyncio.sleep(REQUEST_INTERVAL)
|
await asyncio.sleep(REQUEST_INTERVAL)
|
||||||
|
|
||||||
|
|
||||||
def send_data(client, storable_data, topic=""):
|
def send_data(
|
||||||
|
client: paho.mqtt.client, storable_data: str, topic: str = ""
|
||||||
|
) -> None:
|
||||||
try:
|
try:
|
||||||
log_info(
|
LOGGER.debug(
|
||||||
f"Sending data\ntopic: {MQTT_TOPIC + '/' + topic} \n"
|
f"Sending data\ntopic: {MQTT_TOPIC + '/' + topic} \n"
|
||||||
f"msg: {storable_data}"
|
f"msg: {storable_data}"
|
||||||
)
|
)
|
||||||
|
|
@ -88,18 +98,18 @@ def send_data(client, storable_data, topic=""):
|
||||||
retain=False,
|
retain=False,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
log_info(f"ERROR PUBLISHING DATA TO MQTT BROKER. \n{Exception}")
|
LOGGER.exception("ERROR PUBLISHING DATA TO MQTT BROKER.")
|
||||||
|
|
||||||
|
|
||||||
def format_data_to_serialized_json(info: InverterData) -> str:
|
def format_data_to_serialized_json(info: InverterData) -> str:
|
||||||
data = {"value": info.value, "name": info.name, "unit": info.unit}
|
data = {"value": info.value, "name": info.name, "unit": info.unit}
|
||||||
json_obj = json.dumps(data)
|
json_obj = json.dumps(data)
|
||||||
log_info(f"json_obj: {json_obj}, type: {type(json_obj)}")
|
LOGGER.debug(f"json_obj: {json_obj}, type: {type(json_obj)}")
|
||||||
return json_obj
|
return json_obj
|
||||||
|
|
||||||
|
|
||||||
async def get_inverter_data(
|
async def get_inverter_data(
|
||||||
inverter_client: AsyncHuaweiSolar, register: str, slave_id: int
|
inverter_client: AsyncHuaweiSolar, register: str
|
||||||
) -> InverterData:
|
) -> InverterData:
|
||||||
if DATA_MODE == "INVERTER":
|
if DATA_MODE == "INVERTER":
|
||||||
data = await get_data(inverter_client, register, slave_id)
|
data = await get_data(inverter_client, register, slave_id)
|
||||||
|
|
@ -109,16 +119,19 @@ async def get_inverter_data(
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
log_info("| === START === |")
|
LOGGER.info("| === START === |")
|
||||||
|
try:
|
||||||
mqtt_client = connect()
|
mqtt_client = connect()
|
||||||
|
except TimeoutError:
|
||||||
|
LOGGER.exception("---- CANT CONNECT ----")
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
asyncio.ensure_future(main())
|
asyncio.ensure_future(main(), loop=loop)
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
log_info("| === END === |")
|
LOGGER.info("| === END === |")
|
||||||
loop.close()
|
loop.close()
|
||||||
|
|
|
||||||
19
src/mqtt.py
19
src/mqtt.py
|
|
@ -1,11 +1,12 @@
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
from src.log import log_info
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
mqtt_host = os.getenv("MQTT_HOST", "10.0.0.3")
|
mqtt_host = os.getenv("MQTT_HOST", "mqtt")
|
||||||
broker_port = os.getenv("BROKER_PORT", "1883")
|
broker_port = os.getenv("BROKER_PORT", "1883")
|
||||||
have_credentials = os.getenv("USE_CREDENTIALS", "NO")
|
have_credentials = os.getenv("USE_CREDENTIALS", "NO")
|
||||||
user_name = os.getenv("USER_NAME", "")
|
user_name = os.getenv("USER_NAME", "")
|
||||||
|
|
@ -15,9 +16,9 @@ password = os.getenv("PASSWORD", "")
|
||||||
def on_connect(client, userdata, flags, rc):
|
def on_connect(client, userdata, flags, rc):
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
client.connected_flag = True
|
client.connected_flag = True
|
||||||
log_info("MQTT OK!")
|
LOGGER.info("MQTT OK!")
|
||||||
else:
|
else:
|
||||||
log_info(f"MQTT FAILURE. ERROR CODE: {rc}")
|
LOGGER.error(f"MQTT FAILURE. ERROR CODE: {rc}")
|
||||||
|
|
||||||
|
|
||||||
def setup_mqtt():
|
def setup_mqtt():
|
||||||
|
|
@ -25,15 +26,15 @@ def setup_mqtt():
|
||||||
mqtt_client = mqtt.Client()
|
mqtt_client = mqtt.Client()
|
||||||
mqtt_client.on_connect = on_connect
|
mqtt_client.on_connect = on_connect
|
||||||
mqtt_client.loop_start()
|
mqtt_client.loop_start()
|
||||||
log_info("Connecting to MQTT broker: " + mqtt_host)
|
LOGGER.info("Connecting to MQTT broker: " + mqtt_host)
|
||||||
log_info("Port: " + broker_port)
|
LOGGER.info("Port: " + broker_port)
|
||||||
if have_credentials == "YES":
|
if have_credentials.upper() == "YES":
|
||||||
mqtt_client.username_pw_set(username=user_name, password=password)
|
mqtt_client.username_pw_set(username=user_name, password=password)
|
||||||
mqtt_client.connect(mqtt_host, int(broker_port), 60)
|
mqtt_client.connect(mqtt_host, int(broker_port), 60)
|
||||||
while not mqtt_client.connected_flag:
|
while not mqtt_client.connected_flag:
|
||||||
log_info("...")
|
LOGGER.info("...")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
log_info("START MODBUS...")
|
LOGGER.info("CONNECTED")
|
||||||
return mqtt_client
|
return mqtt_client
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue