second commit
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
'''
|
||||
Created on 23 janv. 2026
|
||||
|
||||
@author: denis
|
||||
'''
|
||||
# process.py
|
||||
#from django.utils.translation import gettext_lazy as _
|
||||
import os
|
||||
os.environ['BOARD_DEVICE']="RPI"
|
||||
import json
|
||||
from threading import Thread, Event
|
||||
from asgiref.sync import async_to_sync #, sync_to_async
|
||||
from channels.layers import get_channel_layer
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
|
||||
from celery import Task
|
||||
from celery.exceptions import Ignore
|
||||
from celery.utils.log import get_task_logger
|
||||
from redis import Redis
|
||||
|
||||
from modules import gpiolib as gpio, devices as dev
|
||||
from . import models
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
redisDB = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0, decode_responses=True)
|
||||
|
||||
class RelayManager:
|
||||
|
||||
def __init__(self):
|
||||
self.shift_out_register = gpio.ShiftOutRegister74HC595(
|
||||
latch_pin=settings.CTL_LATCH_PIN,
|
||||
clock_pin=settings.CTL_CLOCK_PIN,
|
||||
data_pin=settings.CTL_DATA_PIN,
|
||||
number=settings.CTL_NUMBER,
|
||||
)
|
||||
|
||||
def create_relay(self, device, publish=None):
|
||||
return dev.Relay(self.shift_out_register, device.to_register(), publish=publish)
|
||||
|
||||
|
||||
relay_manager = RelayManager()
|
||||
|
||||
|
||||
class RelayProcess(Task):
|
||||
|
||||
def __init__(self, uuid):
|
||||
super().__init__()
|
||||
self.channel_layer = get_channel_layer()
|
||||
self.uuid = uuid
|
||||
self.group = f'relay_{uuid}'
|
||||
self.stop_event = Event()
|
||||
self.heartbeat = 10
|
||||
self.relay = None
|
||||
self.device = None
|
||||
|
||||
def __call__(self, uuid, *args, **kwargs):
|
||||
self.uuid = uuid
|
||||
return self.start(*args, **kwargs)
|
||||
|
||||
|
||||
def redis_pub(self, state, **msg):
|
||||
async_to_sync(self.channel_layer.group_send)(
|
||||
self.group, {
|
||||
"type": 'relay.message',
|
||||
"text": { 'topic': state, **msg }
|
||||
}
|
||||
)
|
||||
self.mqtt_pub(state, **msg)
|
||||
|
||||
|
||||
def mqtt_pub(self, state, **payload):
|
||||
topic = f"relay/{self.uuid}/{state}"
|
||||
payload.pop("uuid", None)
|
||||
redisDB.publish('mqtt_pub', json.dumps({"type": "mqtt", "topic": topic, "payload": payload}))
|
||||
#logger.info(f"mqtt_pub {topic}: {payload}")
|
||||
|
||||
|
||||
def start(self, *args, **kwargs):
|
||||
try:
|
||||
with transaction.atomic():
|
||||
self.device = models.Device.objects.select_for_update().get(uuid=self.uuid)
|
||||
self.stop_event.clear()
|
||||
self.start_services()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Relay error {self.uuid}: {e}")
|
||||
raise Ignore()
|
||||
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
self.redis_pub('state', stop="done")
|
||||
self.stop_event.set()
|
||||
logger.info(f"Relay {self.uuid} stopped.")
|
||||
Event().wait(1.0)
|
||||
finally:
|
||||
self.stop_event.set()
|
||||
gpio.IO_CLEANUP()
|
||||
|
||||
|
||||
def start_services(self):
|
||||
Thread(target=self._listen_to_redis, daemon=True).start()
|
||||
Thread(target=self._relay_process, daemon=True).start()
|
||||
|
||||
|
||||
def _listen_to_redis(self):
|
||||
try:
|
||||
logger.info(f"RelayProcess {self.group}: listen via redisDB")
|
||||
pubsub = redisDB.pubsub()
|
||||
pubsub.subscribe(f"{self.group}", "relay_broadcast", "mqtt_message")
|
||||
try:
|
||||
for message in pubsub.listen():
|
||||
#logger.info(f"{message}")
|
||||
if self.stop_event.is_set():
|
||||
break
|
||||
|
||||
cmd = json.loads(str(message.get('data')))
|
||||
if not isinstance(cmd, dict):
|
||||
continue
|
||||
|
||||
if cmd["type"]=="relay" or cmd["type"]=="mqtt":
|
||||
topic = cmd["topic"]
|
||||
|
||||
if topic == "start":
|
||||
duration = cmd.get("value", 0)
|
||||
self.relay.relay_start(duration=duration)
|
||||
|
||||
elif topic == "stop":
|
||||
self.relay.relay_stop()
|
||||
|
||||
elif topic in ["status", "init"]:
|
||||
self.relay.relay_status()
|
||||
|
||||
elif topic == "halt":
|
||||
self.relay.relay_halt()
|
||||
|
||||
elif topic == "restart":
|
||||
self.relay.relay_restart()
|
||||
except Exception as e:
|
||||
logger.error(f'listen_to_redis: {e}')
|
||||
finally:
|
||||
pubsub.unsubscribe()
|
||||
pubsub.close()
|
||||
|
||||
|
||||
def _relay_process(self):
|
||||
try:
|
||||
logger.info(f"RelayProcess Start {self.uuid}")
|
||||
self.relay = relay_manager.create_relay(self.device, publish=self.redis_pub)
|
||||
self.relay.relay_stop()
|
||||
|
||||
while not self.stop_event.is_set():
|
||||
try:
|
||||
Event().wait(self.device.heartbeat)
|
||||
self.relay.relay_status()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'====> {e}')
|
||||
Event().wait(1.0)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Relay {self.uuid}: {e}")
|
||||
finally:
|
||||
|
||||
logger.info(f"End of relay process: {self.uuid}")
|
||||
self.redis_pub('state', relay="stop")
|
||||
|
||||
Reference in New Issue
Block a user