#!/usr/bin/env python3 """ OSC/Random Example: send random numbers to OSC. This example sends a pseudo-random number between 0 and 1024 to the OSC receiver on UDP port 2222. """ from pythonosc import udp_client from pythonosc import osc_message_builder import time import os import sys import time # import urllib library import urllib.request import urllib.error import socket # import json import json # import argparse import argparse # Logging to file import logging # Errors codes OSC_no_error = 0 OSC_error = 1 OSC_meteobridge_url_error = 11 OSC_meteobridge_http_error = 12 OSC_meteobridge_nosensor_error = 20 OSC_meteobridge_restart = 30 # Debug flags debug_args_print = True debug_json_print = True debug_urllib_print = True debug_restart_print = True debug_osc = False debug_working_directory = os.path.dirname(os.path.realpath(__file__)) # OSC Addresses osc_error_addr = "/env_sensors/anemometer/error" osc_speed_addr = "/env_sensors/anemometer/speed" osc_battery_addr = "/env_sensors/anemometer/battery" osc_age_addr = "/env_sensors/anemometer/age" osc_signal_addr = "/env_sensors/anemometer/signal" # define urllib timeout in seconds url_timeout = 120 # max error number before self restart # max_error_rst = 3 prod_flag = False prod_working_directory = "/usr/local/com.fup.anemometre_daemon" meteobridge_template = "cgi-bin/template.cgi?template={%22time%22:%22[DD][MM][YYYY][hh][mm][ss]%22,%22speed%22:[wind0wind-act],%22lastspeed%22:[wind0wind-lastval],%22battery%22:[wind0lowbat-act.0],%22wind-age%22:[wind0wind-age],%22signal%22:[wind0signal-act.0]}" def send_osc_message(osc_sender, osc_address, osc_arg): msg = osc_message_builder.OscMessageBuilder(address = osc_address) msg.add_arg(osc_arg) osc_sender.send(msg.build()) def main(meteobridge_url, meteobridge_user, meteobridge_passwd, max_host, max_port, errors_restart): error_counter = 0 oscSender = udp_client.UDPClient(max_host, max_port) meteobridge_sensor_req = meteobridge_url + meteobridge_template # Logging logging.basicConfig(filename='fup_anemometer.log', encoding='utf-8', format='%(asctime)s-%(levelname)s:%(message)s', datefmt='%Y/%m/%d %H:%M:%S', level=logging.DEBUG) logging.info("fup_anemometer started") while True: # http auth to meteobridge passman = urllib.request.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, meteobridge_url, meteobridge_user, meteobridge_passwd) authhandler = urllib.request.HTTPBasicAuthHandler(passman) opener = urllib.request.build_opener(authhandler) urllib.request.install_opener(opener) try: response = urllib.request.urlopen(meteobridge_sensor_req, timeout = url_timeout) except urllib.error.HTTPError as e: if debug_urllib_print: print('HTTP Error code: ', e.code) logging.error("Get sensor datas from : " + meteobridge_url + " - HTTP Error code: " + str(e.code)) error_counter += 1 send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_http_error) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error") # msg.add_arg(OSC_meteobridge_http_error) # oscSender.send(msg.build()) # Sleep 5 seconds if error time.sleep(5) except urllib.error.URLError as e: if debug_urllib_print: print('URL Error Reason: ', e.reason) if isinstance(e.reason, socket.timeout): logging.error("Socket timed out from : " + meteobridge_url + " - URL Error Reason: " + str(e.reason)) error_counter += 1 send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_url_error) time.sleep(5) else: logging.error("Get sensor datas from : " + meteobridge_url + " - URL Error Reason: " + str(e.reason)) error_counter += 1 send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_url_error) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error") # msg.add_arg(OSC_meteobridge_url_error) # oscSender.send(msg.build()) # Sleep 5 seconds if error time.sleep(5) else: try: data_json = json.loads(response.read()) if debug_json_print == True: print(data_json) wind_speed = float(data_json["speed"]) wind_lastspeed = float(data_json["lastspeed"]) wind_batt = int(data_json["battery"]) wind_age = int(data_json["wind-age"]) wind_signal = int(data_json["signal"]) except json.JSONDecodeError as e: if debug_json_print: print("Invalid JSON syntax:", e) logging.error("Decode JSON from : " + meteobridge_url + " - Invalid JSON syntax : " + str(e)) error_counter += 1 send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_nosensor_error) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error") # msg.add_arg(OSC_meteobridge_nosensor_error) # oscSender.send(msg.build()) # Sleep 5 seconds if error time.sleep(5) else: error_counter = 0 send_osc_message(oscSender, osc_speed_addr, wind_lastspeed) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/speed") # msg.add_arg(wind_lastspeed) # oscSender.send(msg.build()) send_osc_message(oscSender, osc_battery_addr, wind_batt) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/battery") # msg.add_arg(wind_batt) # oscSender.send(msg.build()) send_osc_message(oscSender, osc_age_addr, wind_age) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/age") # msg.add_arg(wind_age) # oscSender.send(msg.build()) send_osc_message(oscSender, osc_signal_addr, wind_signal) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/signal") # msg.add_arg(wind_signal) # oscSender.send(msg.build()) send_osc_message(oscSender, osc_error_addr, OSC_no_error) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error") # msg.add_arg(OSC_no_error) # oscSender.send(msg.build()) if debug_osc: logging.debug("OSC datas sent") # Sleep 2 seconds if no errors time.sleep(2) # Self restart if error_counter >= errors_restart: send_osc_message(oscSender, osc_error_addr, OSC_meteobridge_restart) # msg = osc_message_builder.OscMessageBuilder(address = "/env_sensors/anemometer/error") # msg.add_arg(OSC_meteobridge_restart) # oscSender.send(msg.build()) time.sleep(1) if debug_restart_print: print("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors") print("Too many errors restarting program ...") logging.error("Current errors count : " + str(error_counter) + " / " + errors_restart + " max errors") logging.error("Too many errors restarting program ...") os.execv(sys.executable, ['python'] + sys.argv) if __name__ == "__main__": parser = argparse.ArgumentParser(description="FUP anemometer for OSC") parser.add_argument('-url', '--url-meteobridge', default='http://192.168.0.39/') parser.add_argument('-u', '--user-meteobridge', default='meteobridge') parser.add_argument('-p', '--passwd-meteobridge',default='meteobridge') parser.add_argument('-mh', '--max-host', default='localhost') parser.add_argument('-mp','--max-port', default=2222, type=int) parser.add_argument('-e', '--errors-restart', default=20, type=int) args = parser.parse_args() # if debug_args_print is True, print arguments if debug_args_print: print('Meteobridge URL:', args.url_meteobridge) print('Meteobridge User:', args.user_meteobridge) print('Meteobridge Password:', args.passwd_meteobridge) print('OSC host:', args.max_host) print('OSC port:', args.max_port) print('Errors restart:', args.errors_restart) main(meteobridge_url=args.url_meteobridge, meteobridge_user=args.user_meteobridge, meteobridge_passwd=args.passwd_meteobridge, max_host=args.max_host, max_port=args.max_port, errors_restart=args.errors_restart)