Programa base Senceive
This commit is contained in:
@@ -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()
|
||||||
Reference in New Issue
Block a user