first commit
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
#
|
||||
# mqtt service
|
||||
#
|
||||
import json, time, logging, ssl
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MqttBase(object):
|
||||
def __init__(self, **p):
|
||||
super().__init__()
|
||||
self.host = p.get('host')
|
||||
self.port = p.get('port')
|
||||
self.username = p.get('username')
|
||||
self.password = p.get('password')
|
||||
self.keepalive = p.get('keepalive')
|
||||
self.use_ssl = p.get('use_ssl', False)
|
||||
self.ca_cert = p.get('ca_cert')
|
||||
self.tls_version = p.get('tls_version', ssl.PROTOCOL_TLSv1_2)
|
||||
self.subscriptions = [(topic, qos) for topic, qos in p.get('topic_subs', [])]
|
||||
self.unsubs = self.client_get_unsubs()
|
||||
self.topic_base = p.get('topic_base', '')
|
||||
|
||||
self.on_message_callback = p.get('on_messages', self._on_message_callback)
|
||||
self.on_bytes_callback = p.get('on_bytes', self._on_bytes_callback)
|
||||
# mqtt Client
|
||||
self.client = mqtt.Client()
|
||||
if self.username:
|
||||
self.client.username_pw_set(username=self.username, password=self.password)
|
||||
if self.use_ssl and self.ca_cert:
|
||||
self.client.tls_set(ca_certs=self.ca_cert, tls_version=self.tls_version)
|
||||
|
||||
self.client.on_connect = self._on_connect
|
||||
self.client.on_disconnect = self._on_disconnect
|
||||
self.client.on_message = self._on_message
|
||||
self.client.on_log = self._on_log
|
||||
|
||||
def client_get_unsubs(self):
|
||||
return [topic for topic, _ in self.subscriptions ]
|
||||
|
||||
|
||||
def client_set_subscriptions(self):
|
||||
self.client.unsubscribe(self.client_get_unsubs())
|
||||
self.client.subscribe(self.subscriptions)
|
||||
logger.info(f"\n client_set_subscription {self.subscriptions}")
|
||||
|
||||
|
||||
def client_add_subscriptions(self, subs=[]):
|
||||
self.subscriptions += subs
|
||||
self.subscriptions = list(set(self.subscriptions))
|
||||
|
||||
|
||||
def _publish_message(self, topic, **payload):
|
||||
try:
|
||||
qos = payload.pop('qos', 0)
|
||||
retain = payload.pop('retain', False)
|
||||
message = json.dumps(payload)
|
||||
self.client.publish(topic, payload=message.encode('utf-8'), qos=qos, retain=retain)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
def _publish_bytes(self, topic, payload, **conf):
|
||||
try:
|
||||
qos = conf.pop('qos', 0)
|
||||
retain = conf.pop('retain', False)
|
||||
self.client.publish(topic, payload=payload, qos=qos, retain=retain)
|
||||
except Exception as e:
|
||||
logger.error(f"\n _publish_bytes error: {e}")
|
||||
|
||||
|
||||
def _on_log(self, mqttc, obj, level, string): # @UnusedVariable
|
||||
pass
|
||||
|
||||
|
||||
def _on_connect_info(self, info):
|
||||
logger.info(info)
|
||||
|
||||
|
||||
def _on_connect(self, client, userdata, flags, rc):
|
||||
msg = f"\n {client._client_id} connected\n status {rc}\n host={self.host}:{self.port}\n username={self.username}"
|
||||
try:
|
||||
if rc:
|
||||
raise
|
||||
self.client_set_subscriptions()
|
||||
self._on_connect_info(msg)
|
||||
except Exception as e:
|
||||
logger.error(f"\n _on_connect error {e}")
|
||||
|
||||
|
||||
def _on_disconnect(self, client, userdata, rc):
|
||||
logger.info(f"\n Disconnected: {client._client_id} with status {rc}")
|
||||
try:
|
||||
j = 3
|
||||
for i in range(j):
|
||||
#client.unsubscribe(self.unsubs)
|
||||
try:
|
||||
client.reconnect()
|
||||
break
|
||||
except Exception as e:
|
||||
if i < j:
|
||||
logger.warn(e)
|
||||
time.sleep(1)
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"\n _on_disconnect error {e}")
|
||||
|
||||
|
||||
def _on_stop_mqtt(self):
|
||||
pass
|
||||
|
||||
|
||||
def _on_message_callback(self, topic, payload):
|
||||
pass
|
||||
|
||||
|
||||
def _on_bytes_callback(self, topic, payload):
|
||||
pass
|
||||
|
||||
|
||||
def _on_message(self, client, userdata, message):
|
||||
try:
|
||||
try:
|
||||
payload = json.loads(message.payload.decode("utf-8"))
|
||||
self.on_message_callback(message.topic, payload)
|
||||
except:
|
||||
self.on_bytes_callback(message.topic, message.payload)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"\n _on_message error {e}\n {message.topic} {message.payload[:80]}")
|
||||
|
||||
|
||||
def connectMQTT(self):
|
||||
self.client.connect_async(self.host, self.port, self.keepalive)
|
||||
|
||||
|
||||
def startMQTT(self):
|
||||
self.connectMQTT()
|
||||
self.client.loop_forever()
|
||||
|
||||
|
||||
def stopMQTT(self):
|
||||
self._on_stop_mqtt()
|
||||
self.client.disconnect()
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
'''
|
||||
Created on 20 avr. 2022
|
||||
|
||||
@author: denis
|
||||
'''
|
||||
import json, yaml
|
||||
import importlib
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
import string, secrets
|
||||
import uuid, socket
|
||||
|
||||
|
||||
class TopicBase:
|
||||
topickeys = {}
|
||||
|
||||
def __init__(self, topics):
|
||||
self.topics = topics.split('/') or []
|
||||
|
||||
def get(self, k):
|
||||
try:
|
||||
return self.topics[self.topickeys.get(k)]
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def arg(cls, topic, k):
|
||||
topics = topic.split('/') or []
|
||||
return topics[cls.get(k)]
|
||||
|
||||
|
||||
|
||||
def yaml_load(f):
|
||||
with open(f, 'r') as stream:
|
||||
return yaml.safe_load(stream)
|
||||
return {}
|
||||
|
||||
|
||||
def yaml_save(f, context):
|
||||
with open(f, 'w') as stream:
|
||||
yaml.dump(context, stream, default_flow_style = False)
|
||||
|
||||
|
||||
|
||||
def bitread(b, bitpos):
|
||||
return (b>>bitpos) & 0x1
|
||||
|
||||
|
||||
def get_fqdn():
|
||||
return socket.getfqdn()
|
||||
|
||||
|
||||
def get_uuid():
|
||||
return str(hex(uuid.getnode()))[2:]
|
||||
|
||||
|
||||
def ts_now(m=1):
|
||||
now = datetime.now().timestamp()*m
|
||||
return int(now)
|
||||
|
||||
|
||||
def random_num(n=16):
|
||||
alphabet = string.digits
|
||||
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
|
||||
|
||||
def random_chars(n=6):
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
|
||||
|
||||
|
||||
def get_apikey(n=32):
|
||||
chars = 'abcdefgh01234ijklABCD4567EFGHIJKLmnopqrstuvwxyz0123456789MNOPQRS789TUVWXYZ'
|
||||
return ''.join(secrets.choice(chars) for i in range(n)) # @UnusedVariable
|
||||
|
||||
|
||||
def str_to_float(n, default='NaN'):
|
||||
try:
|
||||
return float(str(n).strip().replace(',', '.'))
|
||||
except:
|
||||
return default
|
||||
|
||||
def str_to_int(n, default='NaN'):
|
||||
try:
|
||||
return int(str(n).strip())
|
||||
except:
|
||||
return default
|
||||
|
||||
def gps_conv(s, n=1000000, default='NaN'):
|
||||
try:
|
||||
return str( int(Decimal(s)*n) )
|
||||
except:
|
||||
return default
|
||||
|
||||
|
||||
def conv_gps(v, default=None):
|
||||
try:
|
||||
if v == 'NaN':
|
||||
raise
|
||||
return float(Decimal(v)/1000000)
|
||||
except:
|
||||
return default
|
||||
|
||||
|
||||
def js_serialize_array_to_dict(jsarray):
|
||||
d = {}
|
||||
for f in json.loads(jsarray):
|
||||
name = f.get('name')
|
||||
value = f.get('value')
|
||||
if name:
|
||||
d[name] = value
|
||||
return d
|
||||
|
||||
|
||||
def get_instance_class(module):
|
||||
modulename, classname = module.rsplit(".", 1)
|
||||
return getattr(importlib.import_module(modulename), classname)
|
||||
|
||||
|
||||
def gen_keywords(s):
|
||||
c = s.replace(',', ' ').replace('+', ' ')
|
||||
return [ w.strip() for w in c.split(' ') if w]
|
||||
|
||||
|
||||
def gen_device_uuid(n=19):
|
||||
return hex(int(random_num(n)))[2:]
|
||||
|
||||
def get_device_uuid(n=19):
|
||||
return f'0x{gen_device_uuid(n)}'
|
||||
|
||||
def dimensions(s):
|
||||
w, h = s.split('x')
|
||||
return int(w), int(h)
|
||||
|
||||
|
||||
def dim_to_size(w, h):
|
||||
return f'{w}x{h}'
|
||||
|
||||
Reference in New Issue
Block a user