Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e78ce13f |
@@ -1,37 +0,0 @@
|
||||
import json
|
||||
|
||||
class DataObject():
|
||||
def __init__(self):
|
||||
self.currentSpeed = 0
|
||||
self.speed2AVG = 0
|
||||
self.speed10AVG = 0
|
||||
self.speed2Max = 0
|
||||
self.speed10Max = 0
|
||||
self.compass = 0
|
||||
|
||||
def data(self, client, userdata, msg):
|
||||
|
||||
m_in= self.decode( msg.payload )
|
||||
|
||||
try:
|
||||
self.currentSpeed = m_in['windspeed']
|
||||
self.speed2AVG = m_in['speed2AVG']
|
||||
self.speed10AVG = m_in['speed10AVG']
|
||||
self.speed2Max = m_in['speed2max']
|
||||
self.speed10Max = m_in['speed10max']
|
||||
self.compass = m_in['winddirection']
|
||||
except:
|
||||
pass
|
||||
|
||||
def config(self, client, userdata, msg):
|
||||
|
||||
m_in= self.decode( msg.payload )
|
||||
|
||||
try:
|
||||
self.warning = m_in['warning_level']
|
||||
self.alert = m_in['alert_level']
|
||||
except:
|
||||
pass
|
||||
|
||||
def decode(self,payload):
|
||||
return json.loads( payload.decode("utf-8", "ignore") )
|
||||
@@ -1,100 +0,0 @@
|
||||
import os
|
||||
import platform
|
||||
import pygame
|
||||
|
||||
class DriverException(Exception):
|
||||
def __init__(self, driverName):
|
||||
self.driverName = driverName
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.driverName)
|
||||
|
||||
class Screen():
|
||||
screen = None
|
||||
bgColor = None
|
||||
|
||||
def __init__(self, width, height, fullscreen):
|
||||
size = (width, height)
|
||||
|
||||
disp_no = os.getenv('DISPLAY')
|
||||
if disp_no:
|
||||
print ("I'm running under X display = {0}".format(disp_no))
|
||||
self.screen = pygame.display.init()
|
||||
else:
|
||||
print("Try to run from framebuffer...")
|
||||
drivers = ['fbcon','directfb', 'svgalib']
|
||||
|
||||
found = False
|
||||
for driver in drivers:
|
||||
print(driver)
|
||||
if not os.getenv('SDL_VIDEODRIVER'):
|
||||
os.putenv('SDL_VIDEODRIVER', driver)
|
||||
try:
|
||||
self.screen = pygame.display.init()
|
||||
except pygame.error:
|
||||
print("Driver: {0} failed.".format(driver))
|
||||
continue
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
raise Exception('No suitable video driver found!')
|
||||
|
||||
self.realSize = (pygame.display.Info().current_w, pygame.display.Info().current_h)
|
||||
if size[0] > self.realSize[0]:
|
||||
size = (self.realSize[0], size[1])
|
||||
if size[1] > self.realSize[1]:
|
||||
size = (size[0], self.realSize[1])
|
||||
if not fullscreen:
|
||||
self.screen = pygame.display.set_mode(size)
|
||||
else:
|
||||
self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN|pygame.DOUBLEBUF|pygame.HWSURFACE)
|
||||
|
||||
|
||||
def quit(self):
|
||||
pygame.display.quit()
|
||||
|
||||
def update(self):
|
||||
pygame.display.flip()
|
||||
|
||||
def blit(self, surface, x, y):
|
||||
|
||||
self.screen.blit( surface, (x, y) )
|
||||
|
||||
def background(self, color):
|
||||
try:
|
||||
self.screen.fill( pygame.Color(color) )
|
||||
except:
|
||||
self.screen.fill( pygame.Color("white"))
|
||||
finally:
|
||||
self.bgColor = color
|
||||
|
||||
def reset(self):
|
||||
self.background(self.bgColor)
|
||||
|
||||
|
||||
|
||||
def setCaption(self, title):
|
||||
pygame.display.set_caption(title)
|
||||
|
||||
def test(self):
|
||||
# Fill the screen with red (255, 0, 0)
|
||||
self.screen.fill(pygame.Color("red"))
|
||||
# Update the display
|
||||
self.update()
|
||||
|
||||
def getSize(self):
|
||||
return self.screen.get_size()
|
||||
|
||||
def getRealSize(self):
|
||||
return self.realSize
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,49 @@
|
||||
import random
|
||||
from statistics import mean
|
||||
import time
|
||||
|
||||
class AverageValue():
|
||||
def __init__(self): #initialise list values as zero
|
||||
self.list_2= list()
|
||||
self.list_10= list()
|
||||
self.mean_2 =0.0
|
||||
self.mean_10 =0.0
|
||||
self.max_2 =0.0
|
||||
self.max_10 =0.0
|
||||
|
||||
#insert values into list to calculate 2 minutes average
|
||||
def insert_value_list2(self, val):
|
||||
|
||||
if len(self.list_2)>(2*60):
|
||||
self.list_2.pop(0)
|
||||
self.list_2.append(val)
|
||||
else:
|
||||
self.list_2.append(val)
|
||||
return
|
||||
#insert values into list to calculate 10 minutes average
|
||||
def insert_value_list10(self, val):
|
||||
|
||||
if len(self.list_10)>(10*60):
|
||||
self.list_10.pop(0)
|
||||
self.list_10.append(val)
|
||||
else:
|
||||
self.list_10.append(val)
|
||||
return
|
||||
|
||||
#calculate and return 2 minutes average and max
|
||||
def get_m2(self):
|
||||
self.mean_2 =round(mean(self.list_2),2)
|
||||
return self.mean_2
|
||||
def get_max2(self):
|
||||
self.max_2 =round(max(self.list_2),2)
|
||||
return self.max_2
|
||||
|
||||
#calculate and return 10 minutes average and max
|
||||
def get_m10(self):
|
||||
self.mean_10 =round(mean(self.list_10),2)
|
||||
return self.mean_10
|
||||
def get_max10(self):
|
||||
self.max_10 =round(max(self.list_10),2)
|
||||
return self.max_10
|
||||
|
||||
|
||||
+82
-61
@@ -1,71 +1,92 @@
|
||||
[General]
|
||||
fullscreen: True
|
||||
timeToEnd: 5
|
||||
[GENERAL]
|
||||
debug_mode=False
|
||||
path=/var/lib/cloud9/Data/
|
||||
|
||||
[MQTT]
|
||||
topic: DPW/STR/CRAN2/WIND
|
||||
config: DPW/STR/CRAN2
|
||||
host: localhost
|
||||
port: 1884
|
||||
keepalive: 60
|
||||
|
||||
[Color]
|
||||
normal = Black
|
||||
warning = Yellow
|
||||
alert = Red
|
||||
[DB_SETTINGS]
|
||||
db_file_name= WMA001.db
|
||||
tablename= WMA001
|
||||
days_archive = 3
|
||||
|
||||
|
||||
[CurrentSpeed]
|
||||
font_size = 28
|
||||
x = 386
|
||||
y = 226
|
||||
[MQTT_SETTINGS]
|
||||
NumberOfHosts = 2
|
||||
NumberOfPublishers = 3
|
||||
topic_debug=DPW/STR/BUILDING/WIND/DEBUG
|
||||
password = netweb123
|
||||
qos=1
|
||||
|
||||
[AVG2Speed]
|
||||
font_size = 28
|
||||
x = 0
|
||||
y = 0
|
||||
width = 400
|
||||
height = 240
|
||||
[Host1]
|
||||
port = 1883
|
||||
connect = True
|
||||
name = 10.0.1.103
|
||||
client_name = WMA002
|
||||
|
||||
[AVG10Speed]
|
||||
font_size = 28
|
||||
x = 0
|
||||
y = 240
|
||||
width = 400
|
||||
height = 240
|
||||
[Host2]
|
||||
port = 1884
|
||||
connect = True
|
||||
name = 192.168.187.121
|
||||
client_name = WMA002_DISPLAY
|
||||
|
||||
[Publisher1]
|
||||
;#host to which will publish
|
||||
host_n=1
|
||||
;#wether will publish or not
|
||||
pubflag=True
|
||||
#MQTT topic
|
||||
topic = DPW/STR/CRAN2/WIND/
|
||||
;#name of thread (if created)/name of the publisher
|
||||
threadName=Pub_sensor
|
||||
;#read from archive
|
||||
arc_flag=True
|
||||
;#execute in daemon thread
|
||||
daemonTh=False
|
||||
;#source from date
|
||||
Source=sensor
|
||||
;#only true for the sensor source (say if data will be written when not published)
|
||||
store_flag = True
|
||||
;#publish from newest(pseudo online data) or oldest (stored data from last)
|
||||
order=newest
|
||||
;#number of line publications per execution
|
||||
n=1
|
||||
|
||||
[Max2Speed]
|
||||
font_size = 28
|
||||
x = 400
|
||||
y = 0
|
||||
width = 400
|
||||
height = 240
|
||||
|
||||
[Max10Speed]
|
||||
font_size = 28
|
||||
x = 400
|
||||
y = 240
|
||||
width = 400
|
||||
height = 240
|
||||
[Publisher2]
|
||||
host_n=1
|
||||
pubflag=False
|
||||
topic = DPW/STR/CRAN2/WIND/
|
||||
threadName=Pub_archive
|
||||
arc_flag=True
|
||||
daemonTh=True
|
||||
Source=archive
|
||||
store_flag = False
|
||||
order=oldest
|
||||
n=1000
|
||||
|
||||
[Compass]
|
||||
font_size = 20
|
||||
width = 280
|
||||
height = 280
|
||||
x = 260
|
||||
y = 100
|
||||
background = Navy
|
||||
needle_color = Deepskyblue
|
||||
lineLength = 60
|
||||
[Publisher3]
|
||||
host_n=2
|
||||
pubflag=True
|
||||
topic = DPW/STR/CRAN2/WIND/
|
||||
threadName=sensor_to_display
|
||||
arc_flag=False
|
||||
daemonTh=False
|
||||
Source=sensor to display
|
||||
store_flag = False
|
||||
order=''
|
||||
n=0
|
||||
|
||||
[CompassBackground]
|
||||
dashedLineColor = Darkgrey
|
||||
dashsize = 10
|
||||
groundColor = Lightgrey
|
||||
angleOffset = 13
|
||||
|
||||
[Splashscreen]
|
||||
fadein = 0.5
|
||||
fadeout = 0.5
|
||||
solid = 0.5
|
||||
font_size = 20
|
||||
[RS485_SETTINGS]
|
||||
|
||||
baudrate = 9600
|
||||
parity = N
|
||||
stopbits = 1
|
||||
mode = rtu
|
||||
close_port_after_each_call=True
|
||||
debug_serial=False
|
||||
timeout = 0.1
|
||||
precalculate_read_size = True
|
||||
handle_local_echo = False
|
||||
uart=UART4
|
||||
port_name=/dev/ttyO4
|
||||
slave_address=1
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
# instantiate
|
||||
class Configuration():
|
||||
def __init__(self):
|
||||
self.config = ConfigParser()
|
||||
|
||||
# parse existing file
|
||||
self.config.read('/var/lib/cloud9/WMA/config.ini')
|
||||
|
||||
# read General settings
|
||||
self.debug_mode = self.config.getboolean('GENERAL','debug_mode')
|
||||
self.path = self.config.get('GENERAL','path')
|
||||
|
||||
#read DB settings
|
||||
self.db_file_name = self.config.get('DB_SETTINGS','db_file_name')
|
||||
self.table_name = self.config.get('DB_SETTINGS','tablename')
|
||||
self.days_archive = self.config.getint('DB_SETTINGS','days_archive')
|
||||
# read MQTT settings
|
||||
|
||||
self.qos = self.config.getint('MQTT_SETTINGS','qos')
|
||||
self.topic_debug = self.config.get('MQTT_SETTINGS','topic_debug')
|
||||
self.numberOfHosts = self.config.getint('MQTT_SETTINGS','NumberOfHosts')
|
||||
self.numberOfPublishers = self.config.getint('MQTT_SETTINGS','NumberOfPublishers')
|
||||
|
||||
# read rs 485 settings
|
||||
|
||||
self.baudrate = self.config.getint('RS485_SETTINGS','baudrate') # Baud
|
||||
self.parity = self.config.get('RS485_SETTINGS','parity')
|
||||
self.stopbits = bytesize = self.config.getint('RS485_SETTINGS','stopbits')
|
||||
self.mode = self.config.get('RS485_SETTINGS','mode')
|
||||
self.close_port_after_each_call= self.config.getboolean('RS485_SETTINGS','close_port_after_each_call')
|
||||
self.debug_serial=self.config.getboolean('RS485_SETTINGS','debug_serial')
|
||||
self.timeout =self.config.getfloat('RS485_SETTINGS','timeout')
|
||||
self.handle_local_echo = self.config.getboolean('RS485_SETTINGS','handle_local_echo')
|
||||
self.uart=self.config.get('RS485_SETTINGS','uart')
|
||||
self.port_name=self.config.get('RS485_SETTINGS','port_name')
|
||||
self.slave_address=self.config.getint('RS485_SETTINGS','slave_address')
|
||||
@@ -0,0 +1,74 @@
|
||||
import sqlite3
|
||||
import configfile
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from os import remove
|
||||
from json import loads
|
||||
import threading
|
||||
import time
|
||||
|
||||
class Sqlite3_DB():
|
||||
def __init__(self): #constructor to create database connection
|
||||
|
||||
conf = configfile.Configuration()
|
||||
self.dbname=conf.db_file_name
|
||||
self.conn = sqlite3.connect(self.dbname)
|
||||
self.cursor = self.conn.cursor()
|
||||
self.tablename = conf.table_name
|
||||
self.days= conf.days_archive
|
||||
try: #create table if still not exists
|
||||
self.cursor.execute("CREATE TABLE %s(time_date datetime,sensor_data json)"%(conf.table_name))
|
||||
self.conn.commit()
|
||||
except:
|
||||
self.tablecreated=1;
|
||||
self.path=conf.path
|
||||
self.count = 0;
|
||||
|
||||
#function to count the number of rows in SQL database
|
||||
def sql_count(self):
|
||||
self.cursor.execute("SELECT COUNT(sensor_data) FROM %s;"%(self.tablename))
|
||||
numberOfRows = self.cursor.fetchone()[0]
|
||||
return numberOfRows
|
||||
|
||||
#function to select the oldest files of the database
|
||||
def select_oldest(self,number):
|
||||
oldest_data= list()
|
||||
for row in self.cursor.execute("SELECT sensor_data FROM %s LIMIT %d;"%(self.tablename,number)): #DESC FOR NEWES, ASC FOR OLDEST
|
||||
oldest_data.append(row);
|
||||
return(oldest_data)
|
||||
|
||||
#function to select the newest files of the database
|
||||
def select_newest(self,number):
|
||||
newest_data= list()
|
||||
for row in self.cursor.execute("SELECT sensor_data FROM %s ORDER BY rowid DESC LIMIT %d;"%(self.tablename,number)): #DESC FOR NEWES, ASC FOR OLDEST
|
||||
newest_data.append(row);
|
||||
return(newest_data)
|
||||
|
||||
|
||||
def remove_oldests_from_db(self,number):#remove number of old lines from DB
|
||||
while(self.conn.in_transaction):#wait for previous transactions to be over
|
||||
continue;
|
||||
try:
|
||||
self.cursor.execute("DELETE FROM %s LIMIT %d;"%(self.tablename,number)) # remove by order the oldest ones
|
||||
i=0
|
||||
self.conn.commit()
|
||||
while(self.conn.in_transaction):
|
||||
time.sleep(0.0001)
|
||||
|
||||
except:
|
||||
print("Error on Deleting")
|
||||
return;
|
||||
|
||||
def remove_newest_from_db(self,number):#remove number of new lines from DB
|
||||
while(self.conn.in_transaction):#wait for previous transactions to be over
|
||||
continue;
|
||||
try:
|
||||
self.cursor.execute("DELETE FROM %s ORDER BY rowid DESC LIMIT %d;"%(self.tablename,number)) # remove by order the newest ones
|
||||
i=0
|
||||
self.conn.commit()
|
||||
while(self.conn.in_transaction):
|
||||
time.sleep(0.001)
|
||||
|
||||
except:
|
||||
print("Error on Deleting")
|
||||
return;
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
echo Starting display application
|
||||
cd /home/pi/Windmessanlage/Software/Display/
|
||||
DISPLAY=:0 python3 main.py
|
||||
@@ -1,137 +0,0 @@
|
||||
import pygame
|
||||
import math
|
||||
|
||||
class Compass():
|
||||
def __init__(self, font_size, size):
|
||||
pygame.font.init()
|
||||
self.textColor = pygame.Color("white")
|
||||
self.backgroundColor = pygame.Color("White")
|
||||
self.needleColor = pygame.Color("black")
|
||||
|
||||
self.font = pygame.font.Font(pygame.font.get_default_font(), font_size)
|
||||
|
||||
self.surface = pygame.Surface(size, pygame.SRCALPHA)
|
||||
self.size = size
|
||||
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
|
||||
self.backgroundSurface = None
|
||||
|
||||
|
||||
def setX(self, x):
|
||||
self.x = x
|
||||
def getX(self):
|
||||
return self.x
|
||||
|
||||
def setY(self, y):
|
||||
self.y = y
|
||||
def getY(self):
|
||||
return self.y
|
||||
|
||||
def get(self):
|
||||
return self.surface
|
||||
|
||||
def setTextColor(self, color):
|
||||
try:
|
||||
self.textColor = pygame.Color(color)
|
||||
except:
|
||||
self.textColor = pygame.Color("black")
|
||||
|
||||
def setBackgroundColor(self, color):
|
||||
try:
|
||||
self.backgroundColor = pygame.Color(color)
|
||||
except:
|
||||
self.backgroundColor = pygame.Color("white")
|
||||
|
||||
def setNeedleColor(self, color):
|
||||
try:
|
||||
self.needleColor = pygame.Color(color)
|
||||
except:
|
||||
self.needleColor = pygame.Color("black")
|
||||
|
||||
def update(self, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class MiddleNeedle(Compass):
|
||||
def update(self, value):
|
||||
radius = min(self.size[0]//2, self.size[1]//2)
|
||||
pygame.draw.circle( self.surface, self.backgroundColor, (self.size[0]//2, self.size[1]//2), radius)
|
||||
|
||||
|
||||
arrow = pygame.Surface( ((self.size[0]//100*60)//2, self.size[1]//100*60), pygame.SRCALPHA )
|
||||
|
||||
polygon_list = [
|
||||
( arrow.get_width()//2, 0 ), #Middle top
|
||||
( 0, arrow.get_height() ), #bottom left
|
||||
( arrow.get_width()//2, (arrow.get_height()-arrow.get_height()//100*30) ), #middle pos
|
||||
( arrow.get_width(), arrow.get_height() ), #bottom right
|
||||
]
|
||||
|
||||
pygame.draw.polygon(arrow, self.needleColor, polygon_list)
|
||||
arrow = pygame.transform.rotate( arrow, value )
|
||||
self.surface.blit( arrow, ( (self.size[0]//2)-(arrow.get_width()//2), (self.size[1]//2)-(arrow.get_height()//2)))
|
||||
|
||||
text = self.font.render("N", True, self.textColor)
|
||||
self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*10) - text.get_height()//2 ) )
|
||||
|
||||
text = self.font.render("W", True, self.textColor)
|
||||
self.surface.blit( text, ( int(self.size[0]/100*10) - (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
|
||||
|
||||
text = self.font.render("O", True, self.textColor)
|
||||
self.surface.blit( text, ( int(self.size[0]/100*90)- (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
|
||||
|
||||
text = self.font.render("S", True, self.textColor)
|
||||
self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*90) - text.get_height()//2 ) )
|
||||
|
||||
|
||||
class OuterNeedle(Compass):
|
||||
def update(self, value):
|
||||
radius = min(self.size[0]//2, self.size[1]//2)
|
||||
pygame.draw.circle( self.surface, self.backgroundColor, (self.size[0]//2, self.size[1]//2), radius)
|
||||
|
||||
|
||||
if self.backgroundSurface:
|
||||
self.surface.blit( self.backgroundSurface, (0,0) )
|
||||
|
||||
if self.lineLength is None:
|
||||
self.lineLength = 5
|
||||
|
||||
# 0 is down -> +90
|
||||
# alpha = 2 * arcsin (s / 2r); s is bottom line
|
||||
alpha = 2 * math.asin( self.lineLength / (2*radius) )
|
||||
value = math.radians(value) + math.pi/2 #put 0 to bottom
|
||||
bottom_left = self.getPos(value +alpha/2, radius)
|
||||
bottom_left = ( int(bottom_left[0] + radius), bottom_left[1]+radius) #offset to screen middle
|
||||
bottom_right = self.getPos(value -alpha/2, radius)
|
||||
bottom_right = ( int(bottom_right[0] + radius), bottom_right[1]+radius)
|
||||
height_of_segment = self.lineLength/2 * math.tan( alpha / 4 )
|
||||
height_of_triangle = math.sqrt(3) /2 * self.lineLength
|
||||
top = self.getPos(value, radius-height_of_segment-height_of_triangle)
|
||||
top = ( int(top[0] + radius), top[1]+radius )
|
||||
points = [ bottom_left, top, bottom_right ]
|
||||
|
||||
pygame.draw.lines( self.surface, self.needleColor, False, points,3)
|
||||
|
||||
text = self.font.render("N", True, self.textColor)
|
||||
self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*10) - text.get_height()//2 ) )
|
||||
|
||||
text = self.font.render("W", True, self.textColor)
|
||||
self.surface.blit( text, ( int(self.size[0]/100*10) - (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
|
||||
|
||||
text = self.font.render("O", True, self.textColor)
|
||||
self.surface.blit( text, ( int(self.size[0]/100*90)- (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
|
||||
|
||||
text = self.font.render("S", True, self.textColor)
|
||||
self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*90) - text.get_height()//2 ) )
|
||||
|
||||
def getPos(self, alpha, radius):
|
||||
return ( int( radius * math.cos(alpha) ), int( radius * math.sin(alpha) ) )
|
||||
|
||||
def setLineLength(self, length):
|
||||
self.lineLength = length
|
||||
|
||||
def setBackgroundSurface(self, surface):
|
||||
self.backgroundSurface = surface
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import pygame
|
||||
import math
|
||||
|
||||
class Point():
|
||||
# constructed using a normal tupple
|
||||
def __init__(self, point_t = (0,0)):
|
||||
self.x = float(point_t[0])
|
||||
self.y = float(point_t[1])
|
||||
|
||||
# define all useful operators
|
||||
def __add__(self, other):
|
||||
return Point((self.x + other.x, self.y + other.y))
|
||||
def __sub__(self, other):
|
||||
return Point((self.x - other.x, self.y - other.y))
|
||||
def __mul__(self, scalar):
|
||||
return Point((self.x*scalar, self.y*scalar))
|
||||
def __truediv__(self, scalar):
|
||||
return Point((self.x/scalar, self.y/scalar))
|
||||
def __len__(self):
|
||||
return int(math.sqrt(self.x**2 + self.y**2))
|
||||
# get back values in original tuple format
|
||||
def get(self):
|
||||
return (self.x, self.y)
|
||||
|
||||
|
||||
def draw_dashed_line(surf, color, start_pos, end_pos, width=1, dash_length=10):
|
||||
origin = Point(start_pos)
|
||||
target = Point(end_pos)
|
||||
displacement = target - origin
|
||||
length = len(displacement)
|
||||
slope = displacement/length
|
||||
|
||||
for index in range(0, int(length/dash_length), 2):
|
||||
start = origin + (slope * index * dash_length)
|
||||
end = origin + (slope * (index + 1) * dash_length)
|
||||
pygame.draw.line(surf, color, start.get(), end.get(), width)
|
||||
|
||||
if __name__ == "__main__":
|
||||
start =(50,50)
|
||||
end =(100,50)
|
||||
|
||||
surface = pygame.Surface( (200,200) )
|
||||
|
||||
draw_dashed_line( surface, pygame.Color("Black"), start, end, width=1 )
|
||||
@@ -1,53 +0,0 @@
|
||||
import pygame
|
||||
|
||||
class Text():
|
||||
def __init__(self,txt, font_size):
|
||||
pygame.font.init()
|
||||
self.color = pygame.Color("black")
|
||||
self.txt = txt
|
||||
self.font = pygame.font.Font(pygame.font.get_default_font(), font_size)
|
||||
self.text = self.font.render(self.txt, True, self.color)
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
|
||||
def setX(self, x):
|
||||
self.x = x
|
||||
def getX(self):
|
||||
return self.x
|
||||
|
||||
def setY(self, y):
|
||||
self.y = y
|
||||
def getY(self):
|
||||
return self.y
|
||||
|
||||
def get(self):
|
||||
return self.text
|
||||
|
||||
def getSize(self):
|
||||
return self.text.get_size()
|
||||
|
||||
def getWidth(self):
|
||||
return self.text.get_width()
|
||||
|
||||
def setColor(self, color):
|
||||
try:
|
||||
self.color = pygame.Color(color)
|
||||
except:
|
||||
self.color = pygame.Color("black")
|
||||
self.text = self.font.render(self.txt, True, self.color)
|
||||
|
||||
|
||||
class VariableText(Text):
|
||||
def __init__(self, txt, font_size):
|
||||
pygame.font.init()
|
||||
self.color = pygame.Color("black")
|
||||
self.txt = txt+"{}"
|
||||
self.font = pygame.font.Font(pygame.font.get_default_font(), font_size)
|
||||
self.text = self.font.render(self.txt.format(0), True, self.color)
|
||||
|
||||
def setUnit(self, unit):
|
||||
self.txt = self.txt+unit
|
||||
self.unit = unit
|
||||
|
||||
def update(self, value):
|
||||
self.text = self.font.render(self.txt.format(value), True, self.color)
|
||||
@@ -1,55 +0,0 @@
|
||||
import pygame
|
||||
|
||||
class Textbox():
|
||||
def __init__(self, size, x, y, font_size):
|
||||
self.background = pygame.Color("grey")
|
||||
self.surface = pygame.Surface( size )
|
||||
self.surface.fill( self.background )
|
||||
|
||||
self.color = pygame.Color("White")
|
||||
self.fontsize = 20
|
||||
pygame.font.init()
|
||||
|
||||
self.font = pygame.font.Font(pygame.font.get_default_font(), font_size)
|
||||
text = self.font.render("", True, self.color)
|
||||
self.surface.blit( text, (0,0) )
|
||||
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def setText(self, text):
|
||||
self.lines = text.split('\n')
|
||||
self.nr_of_lines = len(self.lines)
|
||||
|
||||
def setTextColor(self, color):
|
||||
try:
|
||||
self.color = pygame.Color(color)
|
||||
except:
|
||||
self.color = pygame.Color("black")
|
||||
|
||||
def setBackgroundColor(self, color):
|
||||
try:
|
||||
self.background = pygame.Color(color)
|
||||
except:
|
||||
self.background = pygame.Color("grey")
|
||||
|
||||
def get(self):
|
||||
return self.surface
|
||||
|
||||
def getX(self):
|
||||
return self.x
|
||||
|
||||
def getY(self):
|
||||
return self.y
|
||||
|
||||
def update(self, value):
|
||||
self.surface.fill( self.background )
|
||||
|
||||
for lineNr, line in enumerate(self.lines):
|
||||
text = self.font.render(line.format(value), True, self.color)
|
||||
spacing = text.get_height()//10
|
||||
x = self.surface.get_width()//2 - text.get_width()//2
|
||||
height_total = self.nr_of_lines * (text.get_height() + spacing)
|
||||
y = self.surface.get_height()//2 - height_total//2 + (lineNr * (text.get_height()+spacing))
|
||||
self.surface.blit( text, (x,y) )
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import json
|
||||
|
||||
|
||||
#returns standard json pack for wind data
|
||||
def json_wma(time,speed, direction,temperature,speed_m2,speed_max2,speed_m10,speed_max10):
|
||||
|
||||
wind = {"time": time, "windspeed": speed, "winddirection" : direction, "temperature": temperature,
|
||||
"speed2AVG": speed_m2,"speed2max": speed_max2,"speed10AVG": speed_m10,"speed10max": speed_max10
|
||||
};
|
||||
|
||||
|
||||
wind_info = json.dumps(wind)
|
||||
|
||||
return wind_info
|
||||
|
||||
def json_concat(json_pack,topic):
|
||||
concat=json.loads(json_pack)
|
||||
topic_json = {"topic": topic};
|
||||
concat.update(topic_json)
|
||||
return json.dumps(concat)
|
||||
|
||||
|
||||
#returns standard json pack for wind data when in debug mode
|
||||
|
||||
def json_debug(time,speed, direction,error_n,kompasswinkel):
|
||||
|
||||
j_debug = {"time": time, "windspeed": speed, "winddirection" : direction, "nErrorsSerial": error_n,
|
||||
"kompasswinkel": kompasswinkel
|
||||
};
|
||||
|
||||
|
||||
|
||||
debug_info = json.dumps(j_debug)
|
||||
|
||||
return debug_info
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,281 +1,173 @@
|
||||
import os
|
||||
import platform
|
||||
import pygame
|
||||
|
||||
"""
|
||||
Created on Tue May 5 15:37:56 2020
|
||||
|
||||
@author: nits
|
||||
connection:
|
||||
green and white = B
|
||||
yellow and brown = A
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import windsensor
|
||||
from jsonwind import json_wma,json_debug,json_concat
|
||||
from json import loads
|
||||
import sighand
|
||||
import mqtt_comm
|
||||
import time
|
||||
import math
|
||||
import avg_values
|
||||
import configfile
|
||||
import db_handle
|
||||
from threading import Timer
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from os import remove
|
||||
import threading
|
||||
from threadf import Publisher
|
||||
import threadf
|
||||
|
||||
import configparser
|
||||
threadf.store_count=0
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
from DataObject import DataObject
|
||||
|
||||
from Screen import Screen
|
||||
from elements.Text import Text, VariableText
|
||||
from elements.Textbox import Textbox
|
||||
from elements.Compass import OuterNeedle
|
||||
from elements.Line import draw_dashed_line, Point
|
||||
|
||||
topic = ""
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
print("Subscribe to {}".format(topic))
|
||||
client.subscribe(topic)
|
||||
|
||||
|
||||
def splashscreen(screen, fadein, solid, fadeout, font_size):
|
||||
screen.background("white")
|
||||
size = screen.getSize()
|
||||
txt = Text("powered by NetWEB Systems", font_size)
|
||||
img = pygame.image.load("resources/NWS.bmp")
|
||||
imgSize = img.get_rect().size
|
||||
surface = pygame.Surface(size)
|
||||
surface.fill(pygame.Color("white"))
|
||||
surface.blit(img, (size[0]//2 - imgSize[0], size[1]//2 - imgSize[1]))
|
||||
surface.blit(txt.get(), (size[0]//2, size[1]//2))
|
||||
|
||||
if (fadein > 0):
|
||||
for alpha in range(0,255): #0 is transparent, 255 is opaque
|
||||
screen.reset()
|
||||
surface.set_alpha(alpha)
|
||||
screen.blit(surface,0,0)
|
||||
screen.update()
|
||||
time.sleep( fadein/255 )
|
||||
def main():
|
||||
#extra threads and parse file
|
||||
conf = configfile.Configuration()
|
||||
|
||||
screen.reset()
|
||||
screen.blit(surface,0,0)
|
||||
screen.update()
|
||||
time.sleep(solid)
|
||||
|
||||
if (fadeout > 0):
|
||||
for alpha in range(0,255): #0 is transparent, 255 is opaque
|
||||
screen.reset()
|
||||
surface.set_alpha(255-alpha)
|
||||
screen.blit(surface,0,0)
|
||||
screen.update()
|
||||
time.sleep( fadeout/255 )
|
||||
|
||||
def getPos(angle, radius, offset):
|
||||
return ( int( radius * math.cos(angle) )+offset, int( radius * math.sin(angle) )+offset)
|
||||
|
||||
def blitRotate(surf, image, pos, originPos, angle):
|
||||
|
||||
# calcaulate the axis aligned bounding box of the rotated image
|
||||
w, h = image.get_size()
|
||||
box = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
|
||||
box_rotate = [p.rotate(angle) for p in box]
|
||||
min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])
|
||||
max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1])
|
||||
|
||||
# calculate the translation of the pivot
|
||||
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
|
||||
pivot_rotate = pivot.rotate(angle)
|
||||
pivot_move = pivot_rotate - pivot
|
||||
|
||||
# calculate the upper left origin of the rotated image
|
||||
origin = (pos[0] - originPos[0] + min_box[0] - pivot_move[0], pos[1] - originPos[1] - max_box[1] + pivot_move[1])
|
||||
|
||||
# get a rotated image
|
||||
rotated_image = pygame.transform.rotate(image, angle)
|
||||
|
||||
# rotate and blit the image
|
||||
surf.blit(rotated_image, origin)
|
||||
|
||||
def buildBackground( size, config ):
|
||||
surface = pygame.Surface( size, pygame.SRCALPHA)
|
||||
|
||||
w = size[0]
|
||||
h = size[1]
|
||||
|
||||
try:
|
||||
dashedLineColor = pygame.Color( config.get('CompassBackground','dashedLineColor') )
|
||||
except:
|
||||
dashedLineColor = pygame.Color("Black")
|
||||
|
||||
try:
|
||||
groundColor = pygame.Color( config.get('CompassBackground','groundColor'))
|
||||
except:
|
||||
groundColor = pygame.Color("Black")
|
||||
|
||||
radius = min( w, h ) // 2
|
||||
angle = config.getint('CompassBackground', 'angleOffset')
|
||||
angle = math.radians( angle )
|
||||
|
||||
dash_length = config.getint('CompassBackground','dashSize')
|
||||
|
||||
#Kaimauer
|
||||
start = getPos( angle, radius, offset=radius )
|
||||
end = getPos( angle+math.pi, radius, offset=radius )
|
||||
draw_dashed_line(surface, dashedLineColor, start, end, width=2, dash_length= dash_length )
|
||||
|
||||
alpha = 2 * math.acos( 1-( (radius-10)/radius ) )
|
||||
start = getPos( (math.pi/2) + (alpha/2) + angle, radius, offset=radius )
|
||||
end = getPos( (math.pi/2) - (alpha/2) + angle, radius, offset=radius )
|
||||
draw_dashed_line(surface, dashedLineColor, start, end, width=2, dash_length= dash_length )
|
||||
|
||||
start = getPos( angle+(math.pi/2), radius//10*8, offset=radius )
|
||||
end = getPos( angle+(math.pi/2), radius//10*1, offset=radius )
|
||||
|
||||
#x1 = Point( start )
|
||||
#x2 = Point( end )
|
||||
#alpha = math.radians(20)
|
||||
#d = len(x1 - x2)
|
||||
#print(d)
|
||||
#length = d * (1/math.sin(math.pi+alpha))
|
||||
#print(length)
|
||||
#x = d * math.cos( alpha )
|
||||
#y = d * math.cos( alpha )
|
||||
#print( x, y)
|
||||
#pygame.draw.line( surface, groundColor, start, (x,y) )
|
||||
|
||||
txt = Text( 'Terminal', 20 )
|
||||
txt.setColor('Lightgrey')
|
||||
txt_surface = pygame.transform.rotate( txt.get(), -math.degrees(angle) )
|
||||
pos = getPos(angle+(math.pi/2), radius/10*2, radius-txt.getWidth()//2)
|
||||
surface.blit( txt_surface, pos )
|
||||
|
||||
#circle_surface = pygame.Surface( size, pygame.SRCALPHA)
|
||||
#pygame.draw.circle( circle_surface, groundColor, (w//2, h//2), radius, width=0, draw_bottom_left=True)
|
||||
#pygame.draw.circle( circle_surface, groundColor, (w//2, h//2), radius, width=0, draw_bottom_right=True)
|
||||
#blitRotate(surface, circle_surface, (w//2,h//2), (w//2,h//2), -math.degrees(angle))
|
||||
|
||||
return surface
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
#load config
|
||||
config = configparser.ConfigParser()
|
||||
config.read("config.ini")
|
||||
|
||||
fullscreen = config.getboolean('General', 'fullscreen')
|
||||
timeToEnd = config.getfloat('General','timetoend')
|
||||
|
||||
screen = Screen(800,480, fullscreen)
|
||||
screen.setCaption("Windmessanlage")
|
||||
screen.background("white")
|
||||
|
||||
#Splashscreen
|
||||
splashscreen(screen, config.getfloat('Splashscreen','fadein'), config.getfloat('Splashscreen','solid'), config.getfloat('Splashscreen','fadeout'), config.getint('Splashscreen','font_size'))
|
||||
|
||||
#-average speed 2min
|
||||
size = ( int(config.get('AVG2Speed','width')), int(config.get('AVG2Speed','height')) )
|
||||
x = int(config.get('AVG2Speed','x'))
|
||||
y = int(config.get('AVG2Speed','y'))
|
||||
averageSpeed2 = Textbox( size, x, y, int(config.get('AVG2Speed','font_size')) )
|
||||
averageSpeed2.setText("Ø 2min:\n{}m/s")
|
||||
averageSpeed2.setBackgroundColor("Black")
|
||||
|
||||
#-average speed 10min
|
||||
size = ( int(config.get('AVG10Speed','width')), int(config.get('AVG10Speed','height')) )
|
||||
x = int(config.get('AVG10Speed','x'))
|
||||
y = int(config.get('AVG10Speed','y'))
|
||||
averageSpeed10 = Textbox( size, x, y, int(config.get('AVG10Speed','font_size')) )
|
||||
averageSpeed10.setText("\nØ 10min:\n{}m/s")
|
||||
averageSpeed10.setBackgroundColor("Black")
|
||||
|
||||
#-max speed 2min
|
||||
size = ( int(config.get('Max2Speed','width')), int(config.get('Max2Speed','height')) )
|
||||
x = int(config.get('Max2Speed','x'))
|
||||
y = int(config.get('Max2Speed','y'))
|
||||
maxSpeed2 = Textbox( size, x, y, int(config.get('Max2Speed','font_size')) )
|
||||
maxSpeed2.setText("Max 2min:\n{}m/s")
|
||||
maxSpeed2.setBackgroundColor("black")
|
||||
|
||||
|
||||
#-max speed 10min
|
||||
size = ( int(config.get('Max10Speed','width')), int(config.get('Max10Speed','height')) )
|
||||
x = int(config.get('Max10Speed','x'))
|
||||
y = int(config.get('Max10Speed','y'))
|
||||
maxSpeed10 = Textbox( size, x, y, int(config.get('Max10Speed','font_size')) )
|
||||
maxSpeed10.setText("\nMax 10min:\n{}m/s")
|
||||
maxSpeed10.setBackgroundColor("Black")
|
||||
|
||||
#compass
|
||||
compass = OuterNeedle(int(config.get('Compass','font_size')), (int(config.get('Compass','width')), int(config.get('Compass','height'))) )
|
||||
compass.setX( int(config.get('Compass','x')) )
|
||||
compass.setY( int(config.get('Compass','y')) )
|
||||
compass.setBackgroundColor( config.get('Compass', 'background') )
|
||||
compass.setNeedleColor( config.get('Compass', 'needle_color') )
|
||||
compass.setLineLength( config.getint('Compass', 'lineLength') )
|
||||
|
||||
compass.setBackgroundSurface( buildBackground( (int(config.get('Compass','width')), int(config.get('Compass','height'))), config ) )
|
||||
|
||||
#-Current speed
|
||||
currentSpeed = VariableText("", int(config.get('CurrentSpeed','font_size')))
|
||||
currentSpeed.setX(int(config.get('CurrentSpeed','x')))
|
||||
currentSpeed.setY(int(config.get('CurrentSpeed','y')))
|
||||
currentSpeed.setUnit("m/s")
|
||||
currentSpeed.setColor("white")
|
||||
|
||||
#MQTT
|
||||
topic = config.get('MQTT','topic')
|
||||
mqttc = mqtt.Client()
|
||||
mqttc.on_connect = on_connect
|
||||
|
||||
data = DataObject()
|
||||
mqttc.message_callback_add( config.get('MQTT','topic'), data.data)
|
||||
mqttc.message_callback_add( config.get('MQTT','config'), data.config)
|
||||
|
||||
mqtt_host = config.get('MQTT', 'host')
|
||||
mqtt_port = int(config.get('MQTT', 'port'))
|
||||
|
||||
|
||||
screen.reset()
|
||||
screen.blit( Text("Try to connect to MQTT server", 24).get(), 0, 0)
|
||||
screen.blit( Text("Server: {0}:{1}".format(mqtt_host, mqtt_port),24).get(), 0, 25)
|
||||
screen.update()
|
||||
pygame.mouse.set_visible(False)
|
||||
|
||||
while(True):
|
||||
try:
|
||||
mqttc.connect(mqtt_host, port=mqtt_port, keepalive=int(config.get('MQTT', 'keepalive')))
|
||||
break
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
print("KeyboardInterrupt or SystemExit")
|
||||
raise
|
||||
except:
|
||||
time.sleep(3)
|
||||
print("Try to reconnect")
|
||||
mqttc.loop_start()
|
||||
|
||||
|
||||
#limit framerate
|
||||
clock = pygame.time.Clock()
|
||||
time_start = 0
|
||||
#initialization of variables and objects
|
||||
|
||||
|
||||
signal_handler=sighand.SignalHandler()
|
||||
wind = windsensor.WindSensor()
|
||||
speed_mean= avg_values.AverageValue()
|
||||
|
||||
# topic = conf.topic
|
||||
days=conf.days_archive
|
||||
topic_debug = conf.topic_debug
|
||||
debug_mode = conf.debug_mode
|
||||
qos_mqtt=conf.qos
|
||||
start = time.time()
|
||||
numberOfHosts=conf.numberOfHosts
|
||||
numberOfPublishers=conf.numberOfPublishers
|
||||
|
||||
#check the hosts and publisher objects
|
||||
|
||||
print("Nr of hosts: ", numberOfHosts)
|
||||
hosts = []
|
||||
print("Nr of publishers: ", numberOfPublishers)
|
||||
publishers = []
|
||||
|
||||
for i in range(1, numberOfHosts+1):
|
||||
name = "Host"+str(i)
|
||||
port = conf.config[name].getint('port')
|
||||
ident = conf.config[name].get('client_name')
|
||||
connect = conf.config[name].getboolean('connect')
|
||||
host_name = conf.config[name].get('name')
|
||||
|
||||
host = mqtt_comm.MQTT_Client(host_name, ident, port,connect)
|
||||
hosts.append(host)
|
||||
|
||||
for host in hosts:
|
||||
if(host.connect):
|
||||
host.client_connect()
|
||||
host.client.loop_start()
|
||||
#create the publisher objects and link them to the hosts
|
||||
for i in range(1, numberOfPublishers+1):
|
||||
name = "Publisher"+str(i)
|
||||
|
||||
pubflag=conf.config[name].getboolean('pubflag')
|
||||
arcflag=conf.config[name].getboolean('arc_flag')
|
||||
daemonTh=conf.config[name].getboolean('daemonTh')
|
||||
st_flag=conf.config[name].getboolean('store_flag')
|
||||
topic = conf.config[name].get('topic')
|
||||
host_n=conf.config[name].getint('host_n')
|
||||
thName=conf.config[name].get('threadName')
|
||||
source=conf.config[name].get('source')
|
||||
order=conf.config[name].get('order')
|
||||
n=conf.config[name].getint('n')
|
||||
print("publisher",i,"daemon =",daemonTh,"archive=",arcflag,"publish=",pubflag)
|
||||
Publisher_n = threadf.Publisher(pubflag,arcflag,topic,hosts[host_n-1],qos_mqtt,daemonTh,thName,source,st_flag,order,n)
|
||||
publishers.append(Publisher_n)
|
||||
|
||||
|
||||
|
||||
#connect to SQL
|
||||
while True:
|
||||
e = pygame.event.poll()
|
||||
if e.type == pygame.QUIT:
|
||||
break
|
||||
|
||||
if e.type == pygame.MOUSEBUTTONDOWN:
|
||||
time_start = time.time()
|
||||
|
||||
if e.type == pygame.MOUSEBUTTONUP:
|
||||
if (time.time() - time_start > timeToEnd):
|
||||
print("{}s".format(time.time() - time_start))
|
||||
break
|
||||
|
||||
|
||||
|
||||
screen.reset()
|
||||
currentSpeed.update(data.currentSpeed)
|
||||
averageSpeed2.update(data.speed2AVG)
|
||||
averageSpeed10.update(data.speed2AVG)
|
||||
maxSpeed2.update(data.speed2Max)
|
||||
maxSpeed10.update(data.speed10Max)
|
||||
compass.update(data.compass)
|
||||
|
||||
|
||||
screen.blit( averageSpeed2.get(), averageSpeed2.getX(), averageSpeed2.getY() )
|
||||
screen.blit( averageSpeed10.get(), averageSpeed10.getX(), averageSpeed10.getY() )
|
||||
screen.blit( maxSpeed2.get(), maxSpeed2.getX(), maxSpeed2.getY() )
|
||||
screen.blit( maxSpeed10.get(), maxSpeed10.getX(), maxSpeed10.getY() )
|
||||
screen.blit( compass.get(), compass.getX(), compass.getY() )
|
||||
screen.blit( currentSpeed.get(), currentSpeed.getX(), currentSpeed.getY() )
|
||||
screen.update()
|
||||
|
||||
#Limit to 30 fps
|
||||
clock.tick(30)
|
||||
try:
|
||||
sqinit=db_handle.Sqlite3_DB();
|
||||
break;
|
||||
except db_handle.sqlite3.Error as er:
|
||||
print('SQLite error: %s' % (' '.join(er.args)))
|
||||
print("Exception class is: ", er.__class__)
|
||||
time.sleep(3)
|
||||
threadf.store_count=sqinit.sql_count();
|
||||
print("Archive has INITIALLY ",threadf.store_count," rows")
|
||||
|
||||
time_json=""
|
||||
while (True):
|
||||
# if(threadf.quit==False):
|
||||
if(time.time() - start > 1.0 or ((time_json)is "")): #Wait 1 second to run loop, if sensor comm fails, will try faster so data won't be lost
|
||||
if(threadf.lock.locked()):
|
||||
threadf.lock.release()#release lock to run the main thread
|
||||
#print("Lock released for running the main routines")
|
||||
threadf.lock.acquire()
|
||||
start = time.time()
|
||||
|
||||
#load data from sensors and calculate mean
|
||||
|
||||
time_act = wind.readDateTime()
|
||||
windspeed_act = wind.readWindSpeed()
|
||||
wind_direct= wind.readWindDirection()
|
||||
wind_temp=wind.readTemp()
|
||||
|
||||
speed_mean.insert_value_list2(windspeed_act)
|
||||
speed_mean.insert_value_list10(windspeed_act)
|
||||
speed_m2=speed_mean.get_m2()
|
||||
speed_max2=speed_mean.get_max2()
|
||||
speed_m10=speed_mean.get_m10()
|
||||
speed_max10=speed_mean.get_max10()
|
||||
|
||||
rm_number=1800 #number of removed lines when requested, 1800 = half an hour
|
||||
if(threadf.store_count>(days*86400+rm_number)):#number of samples per day(size in lines)
|
||||
startc = time.time()
|
||||
|
||||
print('Too many files on the archive, removing older than',days,'days size')
|
||||
sqinit.remove_oldests_from_db(rm_number);#clean DB if DB is too large
|
||||
threadf.store_count=threadf.store_count-rm_number;
|
||||
timec=time.time()-startc
|
||||
print("time taken to remove",rm_number," lines from the old data was: ",timec)#computes and displays the time taken
|
||||
|
||||
|
||||
screen.quit()
|
||||
|
||||
json_pack = json_wma(time_act,windspeed_act,wind_direct,wind_temp,speed_m2,speed_max2,speed_m10,speed_max10)#generate json pack with values
|
||||
time_json=loads(json_pack)["time"];
|
||||
if (time_json is not ""):
|
||||
publishers[0].write_line_db_sub(json_pack)#write line to db using the first publisher object
|
||||
|
||||
for pub in publishers:
|
||||
pub.publish(json_concat(json_pack,pub.topic))
|
||||
#write line to db
|
||||
|
||||
|
||||
|
||||
|
||||
#debug mode
|
||||
if (debug_mode ==1):
|
||||
errorcounter = wind.errorcounter
|
||||
kompasswinkel_act = wind.readCompassAngle()
|
||||
json_pack_debug = json_debug(time_act,windspeed_act,wind_direct,errorcounter,kompasswinkel_act) #print information on console
|
||||
print(json_pack_debug)
|
||||
|
||||
if(threadf.lock.locked()):#release thread lock
|
||||
threadf.lock.release()
|
||||
#check if sensor was read, in case not, it will skip the sleep in order to get the reading faster
|
||||
|
||||
# print("Cycle duration:",time.time()-start,"s")# print time
|
||||
try:
|
||||
if(time_json is not ""):
|
||||
time.sleep(1-(time.time()-start)) #treats exception if time bigger than 1.0s
|
||||
except:
|
||||
print("Cycle>1s lasted:",time.time()-start,"seconds")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
import paho.mqtt.client as mqtt
|
||||
import time
|
||||
import configfile
|
||||
from time import gmtime, strftime
|
||||
import difflib
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class MQTT_Client():
|
||||
|
||||
def __init__(self,host_name, client_name, port,connect): #construtor initialises variables and callback functions
|
||||
conf = configfile.Configuration()
|
||||
#callback functions definition(here because it doesn't work anywhere else)
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
self.connected =1
|
||||
if(rc==1):
|
||||
print("Connected with result code "+str(rc))
|
||||
def on_message(client, userdata, msg):
|
||||
print(msg.topic+" "+str(msg.payload))
|
||||
def on_publish(client, userdata, mid):
|
||||
self.published =1
|
||||
self.last_message=mid;
|
||||
def on_disconnect(client, userdata, rc):
|
||||
self.connected =0
|
||||
print("MQTT Disconnected")
|
||||
|
||||
#initialize variables
|
||||
self.connect=connect
|
||||
self.client_id =client_name
|
||||
self.host_in = host_name
|
||||
self.port_n = port
|
||||
|
||||
self.published = 0
|
||||
self.connected = 0
|
||||
self.last_message = 0
|
||||
self.client = mqtt.Client(client_id=client_name)
|
||||
self.client.on_connect = on_connect
|
||||
self.client.on_message = on_message
|
||||
self.client.on_publish = on_publish
|
||||
self.client.on_disconnect=on_disconnect
|
||||
|
||||
|
||||
|
||||
#create connection to MQTT server
|
||||
def client_connect(self):
|
||||
try:
|
||||
print("Connecting to host: ",self.host_in)
|
||||
self.client.connect(host=self.host_in,port=self.port_n,keepalive=60)
|
||||
except Exception as error:
|
||||
print("Exception:",error);
|
||||
|
||||
|
||||
|
||||
class Host():
|
||||
def __init__(self, Port, Topic, Name, PublishFlag):
|
||||
self.port = Port;
|
||||
self.topic = Topic;
|
||||
self.name = Name
|
||||
self.publishFlag = PublishFlag
|
||||
|
||||
def getTopic(self):
|
||||
return self.topic
|
||||
|
||||
def getPort(self):
|
||||
return self.port
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def publish(self):
|
||||
if self.publishFlag:
|
||||
print("I publish to ", self.topic)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 89 KiB |
+21
@@ -0,0 +1,21 @@
|
||||
import signal
|
||||
import traceback
|
||||
|
||||
|
||||
class SignalHandler:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# register signal handlers
|
||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||
signal.signal(signal.SIGTERM, self.exit_gracefully)
|
||||
|
||||
|
||||
|
||||
def exit_gracefully(self, signum, frame):
|
||||
|
||||
print('captured signal %d' % signum)
|
||||
traceback.print_stack(frame)
|
||||
#print signal code
|
||||
|
||||
raise(SystemExit)
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
from json import loads
|
||||
import db_handle
|
||||
from jsonwind import json_concat
|
||||
import mqtt_comm
|
||||
import time
|
||||
import threading
|
||||
global store_count #global variable, so no need to run sql_count
|
||||
global lock
|
||||
lock = threading.Lock()
|
||||
#thread functions are defined here, as well as global variables
|
||||
class Publisher():
|
||||
def __init__(self,publish_flag,pub_arc_flag,topic,MQTT_client,qos,daemonTh,ThName,source,store_flag,order,n):
|
||||
global lock
|
||||
self.topic=topic;
|
||||
self.qos=qos
|
||||
self.source=source
|
||||
self.client_mqtt = MQTT_client
|
||||
self.publish_flag=publish_flag
|
||||
self.pub_arc_flag=pub_arc_flag
|
||||
self.daemon=daemonTh
|
||||
self.threadName= ThName
|
||||
self.source=source
|
||||
self.store_flag = store_flag
|
||||
self.order =order
|
||||
self.n = n
|
||||
if (daemonTh==True):
|
||||
self.t1=threading.Thread
|
||||
|
||||
|
||||
#function to assure that data has been published
|
||||
def getTopic(self):
|
||||
return self.topic
|
||||
|
||||
def publish_and_wait(self,count,message):
|
||||
if (loads(message)["time"] is not ""):
|
||||
if (self.client_mqtt.connected):
|
||||
(r_code,msg_id)=self.client_mqtt.client.publish(self.topic,message,qos = self.qos)
|
||||
if(r_code==0 and self.source =='archive'):
|
||||
if(msg_id%500==0):
|
||||
print("Message",msg_id, "was delivered with success from the", self.source)
|
||||
return True
|
||||
if(r_code==0 and self.source is not'archive'):
|
||||
print("Message",msg_id, "was delivered with success from the", self.source)
|
||||
return True
|
||||
if(r_code is not 0 and self.store_flag):
|
||||
print("Error no:",r_code,"saving message to archive")
|
||||
self.write_line_db_sub(message)
|
||||
return False
|
||||
else:
|
||||
if(self.store_flag):
|
||||
self.write_line_db_sub(message)
|
||||
|
||||
def publish(self,message=None):
|
||||
global store_count
|
||||
if (self.publish_flag ==True and self.pub_arc_flag == False):
|
||||
self.publish_and_wait(store_count,json_concat(message,self.topic))
|
||||
if (self.publish_flag ==True and self.pub_arc_flag==True and self.daemon==True and store_count>2):
|
||||
self.publish_from_archive()
|
||||
if (self.publish_flag ==True and self.pub_arc_flag==True and self.daemon==False):
|
||||
self.check_publish_stored_files()
|
||||
|
||||
|
||||
#function to write one line to the DB
|
||||
def write_line_db_sub(self,msg_pack):
|
||||
global store_count
|
||||
global lock
|
||||
lock.acquire()
|
||||
data = loads(msg_pack);
|
||||
sqlite_db=db_handle.Sqlite3_DB();
|
||||
sqlite_db.cursor.execute("INSERT into %s values (?, ?);"%(sqlite_db.tablename),[data["time"] , msg_pack])
|
||||
sqlite_db.conn.commit();
|
||||
store_count=store_count+1
|
||||
if (store_count >1):
|
||||
print("Message ",store_count," stored");
|
||||
sqlite_db.conn.close()
|
||||
lock.release()
|
||||
return;
|
||||
|
||||
#function to publish from archive lines and delete them after
|
||||
|
||||
def check_publish_stored_files(self):
|
||||
|
||||
if(self.client_mqtt.connected):
|
||||
starter = time.time()#count time to execute the function
|
||||
global store_count
|
||||
sqlite_db=db_handle.Sqlite3_DB()
|
||||
|
||||
if(store_count>0):
|
||||
if (self.order=='oldest'):
|
||||
print("SQL Archive has",store_count,"rows.")
|
||||
if (store_count >self.n):
|
||||
end= self.n;
|
||||
else:
|
||||
end= store_count
|
||||
i=0
|
||||
|
||||
if (self.order=='oldest'): # if the published files are gonna be the oldest (publish from archive)
|
||||
|
||||
for row in sqlite_db.select_oldest(end):
|
||||
lock.acquire()
|
||||
if(self.publish_and_wait(store_count,json_concat(row[0],self.topic))):
|
||||
store_count = store_count-1
|
||||
i=i+1
|
||||
time.sleep(0.002)
|
||||
if (lock.locked()):
|
||||
lock.release()
|
||||
|
||||
sqlite_db.remove_oldests_from_db(i)
|
||||
time_publish=time.time()-starter
|
||||
|
||||
# print("############################################################")
|
||||
# print("time taken to publish",end,self.order," numbers was",time_publish)
|
||||
# print("############################################################")
|
||||
|
||||
|
||||
if (self.order=='newest'): # if the published files are gonna be the newest (publish actual data from sensor)
|
||||
|
||||
end = 1 #only allows 1 line to be selected, since there's no sleep
|
||||
for row in sqlite_db.select_newest(end):
|
||||
if(self.publish_and_wait(store_count,json_concat(row[0],self.topic))):
|
||||
store_count = store_count-1
|
||||
i=i+1
|
||||
sqlite_db.remove_newest_from_db(i)#delete line
|
||||
sqlite_db.conn.commit()
|
||||
sqlite_db.conn.close()
|
||||
|
||||
|
||||
|
||||
return
|
||||
#thread that runs when publishing from archive
|
||||
def publish_from_archive(self):
|
||||
ThNames= [];
|
||||
for thread in threading.enumerate():
|
||||
ThNames.append(thread.name);
|
||||
if (self.threadName in ThNames):
|
||||
print("Thread",self.threadName,"is busy")#check if not empty
|
||||
else:
|
||||
self.t1 = threading.Thread(name =self.threadName,target=self.check_publish_stored_files, args=())
|
||||
self.t1.setDaemon(True);
|
||||
self.t1.start()
|
||||
|
||||
def write_line_db_sub(self,msg_pack):
|
||||
global store_count
|
||||
data = loads(msg_pack);
|
||||
sqlite_db=db_handle.Sqlite3_DB();
|
||||
sqlite_db.cursor.execute("INSERT into %s values (?, ?);"%(sqlite_db.tablename),[data["time"] , msg_pack])
|
||||
sqlite_db.conn.commit();
|
||||
store_count=store_count+1
|
||||
if (store_count>1):
|
||||
print("Message ",store_count," stored");
|
||||
sqlite_db.conn.close()
|
||||
return;
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Tue May 5 14:52:57 2020
|
||||
|
||||
@author: nits
|
||||
"""
|
||||
|
||||
import minimalmodbus
|
||||
import time
|
||||
|
||||
import configfile
|
||||
conf = configfile.Configuration()
|
||||
import Adafruit_BBIO.UART as UART
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class WindSensor():
|
||||
|
||||
def __init__(self): #initialise network connection and parameters
|
||||
conf = configfile.Configuration()
|
||||
UART.setup(conf.uart)
|
||||
|
||||
self.inst = minimalmodbus.Instrument(conf.port_name, conf.slave_address) # port name, slave address (in decimal)
|
||||
self.inst.serial.baudrate = conf.baudrate # Baud
|
||||
self.inst.serial.parity = conf.parity
|
||||
self.inst.serial.stopbits = conf.stopbits
|
||||
self.inst.mode = conf.mode
|
||||
self.inst.close_port_after_each_call=conf.close_port_after_each_call
|
||||
self.inst.debug=conf.debug_serial
|
||||
self.inst.serial.timeout = conf.timeout
|
||||
self.inst.handle_local_echo = conf.handle_local_echo
|
||||
self.error=0
|
||||
self.errorcounter = 0
|
||||
self.cyclecounter = 0
|
||||
|
||||
|
||||
|
||||
#read temperature from sensor
|
||||
def readTemp(self):
|
||||
try:
|
||||
temp = self.inst.read_long(30405,4,True)/10
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
#time.sleep(0.1)
|
||||
return 0
|
||||
return temp
|
||||
|
||||
#read speed from sensor
|
||||
def readWindSpeed(self):
|
||||
try:
|
||||
temp = self.inst.read_long(30003,4,False)/10
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
self.error=1
|
||||
|
||||
return 0
|
||||
return temp
|
||||
#read wind direction from sensor
|
||||
def readWindDirection(self):
|
||||
try:
|
||||
temp = self.inst.read_long(30203,4,False)/10
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
# time.sleep(0.1)
|
||||
error=1
|
||||
|
||||
return 0
|
||||
return temp
|
||||
|
||||
#read date and time from sensor
|
||||
def readDateTime(self):
|
||||
try:
|
||||
date = self.inst.read_long(34601,4,False)
|
||||
uhr = self.inst.read_long(34603,4,False)
|
||||
date_time = datetime.strptime(str(date)+str(uhr), '%Y%m%d%H%M%S');
|
||||
date_info=date_time.strftime('%Y-%m-%d %H:%M:%S');
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
return ""
|
||||
return date_info
|
||||
|
||||
#read compass angle from sensor
|
||||
def readCompassAngle(self):
|
||||
try:
|
||||
temp = self.inst.read_long(35081,4,False)/10
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
|
||||
error=1
|
||||
return 0
|
||||
|
||||
return temp
|
||||
#function to read parameter
|
||||
def readP(self,address):
|
||||
try:
|
||||
param = self.inst.read_long(address,3,False)
|
||||
print("The value of the address ",address,"is: ",param)
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
|
||||
error=1
|
||||
return 0
|
||||
|
||||
#function to set parameter
|
||||
def setP(self,address,value):
|
||||
try:
|
||||
param = self.inst.write_register(address,value,functioncode=16)
|
||||
print("The value of the address ",address,"has been changed to: ",value)
|
||||
except Exception as error:
|
||||
print ("[!] Exception occurred: ", error)
|
||||
self.errorcounter = self.errorcounter + 1
|
||||
|
||||
error=1
|
||||
return 0
|
||||
return 1
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Service to start WMA Client
|
||||
[Service]
|
||||
Type=simple
|
||||
RestartSec=10
|
||||
Restart=always
|
||||
ExecStart=/var/lib/cloud9/WMA/wma.sh
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user