Programa base Senceive

This commit is contained in:
2025-11-18 10:39:10 +01:00
commit 5fb44c334d
+272
View File
@@ -0,0 +1,272 @@
import argparse
import binascii
from email import header
import textwrap
import pika
import json
from furl import furl
from eventstream.event_pb2 import Event
from eventstream.data_pb2 import SensorModel
from eventstream.status_pb2 import GatewayStatus, HostConnectionReport
import google.protobuf.text_format
import google.protobuf.json_format
import requests
from requests.auth import HTTPBasicAuth
import mysql.connector
import os
from xml.dom import minidom
from xml.sax.handler import ContentHandler
import xml.sax
from datetime import datetime
from zoneinfo import ZoneInfo
class SenceiveIOConsumer:
def _internal_callback(self, stream_name, channel, method_frame, header_frame, body, array_sensores):
#Get the stream offset
stream_offset = header_frame.headers['x-stream-offset']
#Create a blank protocol buffers message of type Event
event = Event()
#Decode the message payload and populate the fields
event.ParseFromString(body)
if self.callback_fn(stream_name, stream_offset, event, array_sensores) == True:
self.offsets[stream_name] = stream_offset
channel.basic_ack(delivery_tag=method_frame.delivery_tag)
def _make_callback(self, stream_name, array_sensores):
# Set up a callback lambda for each stream which bakes in the
# channel name and reference to self
# Parameters to the lambda are dictated by the AMQP library
# An alternative approach to distingushing streams when messages arrive
# is to record the Consumer Tag returned from basic_consume; this tag
# is supplied in the method_frame parameter
# Creating the lambda is done in a separate function to avoid issues
# related to late binding
# https://docs.python-guide.org/writing/gotchas/#late-binding-closures
def cb(channel, method_frame, header_frame, body):
self._internal_callback(stream_name, channel, method_frame, header_frame, body, array_sensores)
return cb
def __init__(self, connection_string, callback_fn, stream_names, offsets_filename, start_at=None, array_sensores=None):
parameters = pika.URLParameters(connection_string)
self.connection = pika.BlockingConnection(parameters)
self.channel = self.connection.channel()
self.array_sensores = array_sensores
self.channel.basic_qos(
prefetch_count=500 #500 message prefetch limit
)
self.callback_fn = callback_fn
self.offsets_filename = offsets_filename
self.offsets = {}
# Consume from each of the available streams
for n in stream_names:
# The x-stream-offset argument controls where in the stream we
# start reading from
consume_args = None
if start_at is not None:
consume_args = {'x-stream-offset': start_at}
elif n in self.offsets:
consume_args = {'x-stream-offset': self.offsets[n] + 1}
self.channel.basic_consume(n, self._make_callback(n,self.array_sensores), arguments=consume_args)
def consume_until_keyboard_interrupt(self):
try:
self.channel.start_consuming()
except KeyboardInterrupt:
try:
self.channel.stop_consuming()
except pika.exceptions.AMQPError:
pass
def close(self):
try:
self.connection.close()
except:
pass
def insert_mysql(sensor_id, id_lectura, tiempo, data):
cadena_sql_general = "insert into lecturas (sensor_id,id_lectura,fecha,lectura) values('" + str(sensor_id) + "'," + str(id_lectura) + ",'" + tiempo + "'," + str(data) + ");"
conexion_mysql = mysql.connector.connect(user="sincroIns", password="teknes", host="192.168.1.110", database="campo_bolueta", port="3306")
cursor = conexion_mysql.cursor()
cursor.execute(cadena_sql_general)
conexion_mysql.commit()
conexion_mysql.close()
def print_message_min(stream_name, stream_offset, event, array_sensores):
event_type = event.WhichOneof('event_data') or 'Unknown'
# DATO
if event_type == 'data_sample':
datos_evento = event.data_sample
tiempo = event.event_time.ToJsonString()
mac_sensor_recibido = event.source_device_id
nombre_canal = SensorModel.Name(datos_evento.sensor_model)
data = datos_evento.data
try:
dt = datetime.strptime(tiempo, "%Y-%m-%dT%H:%M:%SZ")
except:
dt = datetime.strptime(tiempo, "%Y-%m-%dT%H:%M:%S.%fZ")
dt = dt.replace(tzinfo=ZoneInfo("UTC"))
dt_madrid = dt.astimezone(ZoneInfo("Europe/Madrid"))
tiempo = dt_madrid.strftime("%Y-%m-%d %H:%M:%S")
#print(str(event.event_time.ToJsonString()) + " " + str(event.source_device_id) + " " + str(SensorModel.Name(datos_evento.sensor_model)) + " " + str(datos_evento.data) + " " + str(datos_evento.units))
id_lectura = 0
for x in array_sensores:
teknes_sensor = x.get("teknes")
senceive_sensor_mac = x.get("senceive")
if senceive_sensor_mac == mac_sensor_recibido:
id_lectura = id_lectura+1
if x.get("teknes").find("DIST")!= -1:
if nombre_canal == "OdsDistance":
print(x.get("teknes"))
sensor_id = x.get("teknes")
data = data/1000
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif nombre_canal == "InclinometerHighResX":
sensor_id = x.get("teknes").replace("DIST","CLIN")
print(sensor_id + "_X")
sensor_id = sensor_id + "_X"
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif nombre_canal == "InclinometerHighResY":
sensor_id = x.get("teknes").replace("DIST","CLIN")
print(sensor_id + "_Y")
sensor_id = sensor_id + "_Y"
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif nombre_canal == "InclinometerHighResZ":
sensor_id = x.get("teknes").replace("DIST","CLIN")
print(sensor_id + "_Z")
sensor_id = sensor_id + "_Z"
insert_mysql(sensor_id, id_lectura, tiempo, data)
else:
if nombre_canal == "InclinometerHighResX":
print(x.get("teknes") + "_X")
sensor_id = x.get("teknes") + "_X"
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif nombre_canal == "InclinometerHighResY":
print(x.get("teknes") + "_Y")
sensor_id = x.get("teknes") + "_Y"
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif nombre_canal == "InclinometerHighResZ":
print(x.get("teknes") + "_Z")
sensor_id = x.get("teknes") + "_Z"
insert_mysql(sensor_id, id_lectura, tiempo, data)
elif event_type == 'gateway_status':
e = event.gateway_status
sensor_id = "Gateway_bateria"
id_lectura = 1
tiempo = event.event_time.ToJsonString()
data = e.main_battery_v
try:
dt = datetime.strptime(tiempo, "%Y-%m-%dT%H:%M:%SZ")
except:
dt = datetime.strptime(tiempo, "%Y-%m-%dT%H:%M:%S.%fZ")
dt = dt.replace(tzinfo=ZoneInfo("UTC"))
dt_madrid = dt.astimezone(ZoneInfo("Europe/Madrid"))
tiempo = dt_madrid.strftime("%Y-%m-%d %H:%M:%S")
print(sensor_id)
insert_mysql(sensor_id, id_lectura, tiempo, data)
return True
def main():
username = 'senceive_io.6901cd1f16e0673062ec4721'
password = 'p0h9BodsKe6WfozRdsMkqbN2tdU6drQDtnZGLQ9zDNz0dwnV'
home_uri = 'https://senceive.io'
start_at = None
offsets_file = 'resume.json'
# Cargar configuracion para el cambio de nombre de los sensores
array_sensores = []
f = open("/home/teknes/senceive-teknes/sensores.txt", "r")
for x in f:
y = x.strip()
dotpos = y.find(";")
sensor = y[:dotpos]
nombre_senceive = sensor
sensor = y[dotpos+1:]
nombre_teknes = sensor
array_sensores.append({"teknes":nombre_teknes,"senceive":nombre_senceive})
f.close()
# Log in to the system and retrieve the Consumer Account details,
# including the available streams
consumer_info_url = furl(home_uri)
consumer_info_url.path = 'api/consumers/current'
request = requests.get(consumer_info_url.url, auth=HTTPBasicAuth(username, password))
if request.status_code != 200:
print('ERROR: Unable to retrieve Consumer Account Details, status={}'.format(request.status_code))
return
account = request.json()
# Insert the credentials into the connection string as the API will not
# include the password in any connection string apart from the one issued
# on first creation
connectionString = account['connectionString']
cs_url = furl(connectionString)
cs_url.password = password
connectionString = cs_url.url
# Display Consumer Account details including list of available streams
print('Consumer Account: {0[_id]} ({0[name]})'.format(account))
webui_url = furl(home_uri)
webui_url.path = 'deviceGroups/{0[deviceGroup]}/consumers/{0[_id]}'.format(account)
print(' ' + webui_url.url)
print('Broker Connection String: {}'.format(connectionString))
print()
print('{:49} {:25} {:30}'.format('Stream Identifier', 'Tenant Name', 'Device Group Name'))
for s in account['streams']:
print('{0[stream]:49} {0[tenantName]:25} {0[deviceGroupName]:30}'.format(s))
print()
callback = print_message_min
stream_names = [s['stream'] for s in account['streams']]
consumer = SenceiveIOConsumer(
connectionString,
callback,
stream_names,
offsets_file,
start_at,
array_sensores)
consumer.consume_until_keyboard_interrupt()
consumer.close()
if __name__ == '__main__':
main()