diff --git a/compLib/Encoder.py b/compLib/Encoder.py index 3ede960..75ac3a0 100644 --- a/compLib/Encoder.py +++ b/compLib/Encoder.py @@ -2,6 +2,7 @@ import atexit from enum import Enum from compLib.LogstashLogging import Logging +from compLib.MetricsLogging import MetricsLogging from compLib.Spi import Spi, Register MOTOR_COUNT = 4 @@ -47,7 +48,8 @@ class Encoder(object): diff = Encoder.read_raw(port) - encoder_start_values[port] if diff > 2 ** 31: diff -= 2 ** 32 - + + MetricsLogging.put("Encoder", diff, port) return diff @staticmethod diff --git a/compLib/IRSensor.py b/compLib/IRSensor.py index 8f2cf3a..f2747af 100644 --- a/compLib/IRSensor.py +++ b/compLib/IRSensor.py @@ -1,6 +1,6 @@ from compLib.LogstashLogging import Logging +from compLib.MetricsLogging import MetricsLogging from compLib.Spi import Spi, Register -import spidev SENSOR_COUNT = 5 @@ -14,18 +14,20 @@ class IRSensor(object): if sensor <= 0 or sensor > SENSOR_COUNT: raise IndexError("Invalid sensor specified!") + result = 0 if sensor == 1: - return Spi.read(Register.IR_1_H, 2) + result = Spi.read(Register.IR_1_H, 2) elif sensor == 2: - return Spi.read(Register.IR_2_H, 2) + esult = Spi.read(Register.IR_2_H, 2) elif sensor == 3: - return Spi.read(Register.IR_3_H, 2) + esult = Spi.read(Register.IR_3_H, 2) elif sensor == 4: - return Spi.read(Register.IR_4_H, 2) + esult = Spi.read(Register.IR_4_H, 2) elif sensor == 5: - return Spi.read(Register.IR_5_H, 2) - else: - return 0 + esult = Spi.read(Register.IR_5_H, 2) + + MetricsLogging.put("Infrared", result, sensor) + return result @staticmethod def set(sensor: int, on: bool): diff --git a/compLib/MetricsLogging.py b/compLib/MetricsLogging.py new file mode 100644 index 0000000..f696c0c --- /dev/null +++ b/compLib/MetricsLogging.py @@ -0,0 +1,84 @@ +from influxdb_client import InfluxDBClient, Point, WritePrecision +import socket +import uuid +import os +import queue +import datetime +import threading +import requests + +CONCURRENCY = 2 + +HOSTNAME = socket.gethostname() +RUN_TRACE = str(uuid.uuid4()) + +TOKEN = "aCdxnntw-Zp3agci8Z32lQAR_ep6MhdmWOJG7ObnoikYqe7nKAhFYx1jVGBpipQuId79SC4Jl0J6IBYVqauJyw==" +ORG = "robo4you" +BUCKET = "compAIR" + +INFLUX_HOST = "https://influxdb.comp-air.at" + +EXTENSIVE_LOGGING = os.getenv("EXTENSIVE_LOGGING", "True") +if EXTENSIVE_LOGGING == "True": + EXTENSIVE_LOGGING = True +else: + EXTENSIVE_LOGGING = False + + +influx_client = InfluxDBClient(url=INFLUX_HOST, token=TOKEN) +write_api = influx_client.write_api() + +point_queue = queue.Queue() +workers = [] + +class MetricsLogging(): + + @staticmethod + def is_influx_reachable(): + try: + r = requests.get(INFLUX_HOST) + if r.status_code == 200: + return True + else: + print(f"Could not connect to {INFLUX_HOST} -> ERROR CODE: {r.status_code}!") + return False + except requests.exceptions.RequestException as identifier: + print(f"Could not connect to {INFLUX_HOST}!") + + @staticmethod + def put(sensorType, value, port): + if EXTENSIVE_LOGGING: + point = Point(sensorType) \ + .tag("host", HOSTNAME) \ + .tag("runID", RUN_TRACE) \ + .tag("port", port) \ + .field("value", value) \ + .time(datetime.datetime.utcnow(), WritePrecision.MS) + point_queue.put_nowait(point) + + @staticmethod + def worker(): + while True: + point = point_queue.get() + if point is None: # Kill signal + return + + try: + write_api.write(BUCKET, ORG, point) + + finally: + point_queue.task_done() + + @staticmethod + def start_workers(): + global EXTENSIVE_LOGGING + if EXTENSIVE_LOGGING: + if MetricsLogging.is_influx_reachable(): + EXTENSIVE_LOGGING = False + for i in range(CONCURRENCY): + worker = threading.Thread(target=MetricsLogging.worker, daemon=True) + worker.start() + workers.append(worker) + + +MetricsLogging.start_workers() diff --git a/compLib/Motor.py b/compLib/Motor.py index 858041d..ea6e05f 100644 --- a/compLib/Motor.py +++ b/compLib/Motor.py @@ -2,6 +2,7 @@ import atexit from enum import IntEnum from compLib.LogstashLogging import Logging +from compLib.MetricsLogging import MetricsLogging from compLib.Spi import Spi, Register MOTOR_COUNT = 4 @@ -45,14 +46,13 @@ class Motor(object): Spi.write(Register.PWM_4_CTRL, 1, int(mode)) @staticmethod - def power_raw(port: int, percent: float): + def power_raw(port: int, percent: float, log_metric = True): """Set specified motor to percentage power :param port: Port, which the motor is connected to. 1-4 :param percent: Percentage of max speed. between -100 and 100 :raises: IndexError """ - Logging.get_logger().debug(f"Motor.power {port} {percent}") if port <= 0 or port > MOTOR_COUNT: raise IndexError("Invalid Motor port specified!") @@ -60,6 +60,9 @@ class Motor(object): if percent < -100 or percent > 100: raise IndexError("Invalid Motor speed specified! Speed is between -100 and 100 percent!") + if log_metric: + MetricsLogging.put("MotorRaw", percent, port) + mode = MotorMode.COAST if percent < 0: percent = abs(percent) @@ -80,12 +83,14 @@ class Motor(object): :param percent: Percentage of max speed. between -100 and 100 :raises: IndexError """ + raw_power = 0 if percent > 0: - Motor.power_raw(port, Motor.__linearizePower(MOTOR_CURVE, percent)) + raw_power = Motor.__linearizePower(MOTOR_CURVE, percent) elif percent < 0: - Motor.power_raw(port, -Motor.__linearizePower(MOTOR_CURVE, -percent)) - else: - Motor.power_raw(port, 0) + raw_power = -Motor.__linearizePower(MOTOR_CURVE, -percent) + + MetricsLogging.put("Motor", percent, port, False) + Motor.power_raw(port, raw_power) @staticmethod def all_off(): diff --git a/compLib/Servo.py b/compLib/Servo.py index 183986b..cf50d43 100644 --- a/compLib/Servo.py +++ b/compLib/Servo.py @@ -1,36 +1,36 @@ -from compLib.PCA9685 import PCA9685 +# from compLib.PCA9685 import PCA9685 -SERVO_COUNT = 10 +# SERVO_COUNT = 10 -pwm = PCA9685(0x40, debug=True) -pwm.setPWMFreq(50) +# pwm = PCA9685(0x40, debug=True) +# pwm.setPWMFreq(50) -MIN_ANGLE = -90.0 -MAX_ANGLE = 90.0 +# MIN_ANGLE = -90.0 +# MAX_ANGLE = 90.0 -class Servo: - """Control the servo ports on the robot - """ +# class Servo: +# """Control the servo ports on the robot +# """ - @staticmethod - def set_position(channel: int, angle: int, offset: float =90): - """Set position of servo connected to port +# @staticmethod +# def set_position(channel: int, angle: int, offset: float =90): +# """Set position of servo connected to port - :param channel: channel between 0 and 7 - :param angle: Angle of servo - """ - if channel < 0 or channel >= SERVO_COUNT: - raise IndexError("Invalid Servo channel specified!") +# :param channel: channel between 0 and 7 +# :param angle: Angle of servo +# """ +# if channel < 0 or channel >= SERVO_COUNT: +# raise IndexError("Invalid Servo channel specified!") - angle = max(min(angle, MAX_ANGLE), MIN_ANGLE) +# angle = max(min(angle, MAX_ANGLE), MIN_ANGLE) - pwm.setServoPulse(channel + 8, 500+int((angle+offset)/0.09)) +# pwm.setServoPulse(channel + 8, 500+int((angle+offset)/0.09)) - @staticmethod - def setup_position(): - """Set position of servos to the position used during the setup process - """ +# @staticmethod +# def setup_position(): +# """Set position of servos to the position used during the setup process +# """ - Servo.set_position(0, 0) - Servo.set_position(1, 0) +# Servo.set_position(0, 0) +# Servo.set_position(1, 0) diff --git a/compLib/__init__.py b/compLib/__init__.py index e42c956..c0efb79 100644 --- a/compLib/__init__.py +++ b/compLib/__init__.py @@ -1,26 +1,40 @@ __version__ = "0.1.5-1" +import importlib import compLib.LogstashLogging -import compLib.Spi -import compLib.Reset -import compLib.Encoder -import logging -import apt -try: - __versions = apt.Cache()["python3-complib"].versions - if len(__versions) != 1: - print(f"Starting compLib! \033[91mVersion: {__version__} is outdated\033[0m\n" - f"\033[92m[!] run the command 'sudo apt update && sudo apt install python3-complib' to install the newest version\033[0m") - else: - print(f"Starting compLib! \033[92mVersion: {__version__} is up to date\033[0m") -except Exception as e: - compLib.LogstashLogging.Logging.get_logger().error(f"error during checking apt package version -> {str(e)}") - print(f"\033[91merror during checking apt package version -> {str(e)}\033[0m\n") -print(f"\033[34mInitializing chipmunk board...\033[0m") -compLib.Reset.Reset.reset_bot() -compLib.Spi.Spi.health_check() -compLib.Spi.Spi.start_health_check_loop() -compLib.Encoder.Encoder.clear_all() -print(f"\033[34mReady\033[0m\n") \ No newline at end of file +apt_found = importlib.util.find_spec("apt") is not None +spi_found = importlib.util.find_spec("spidev") is not None + + +if apt_found: + import apt + + try: + __versions = apt.Cache()["python3-complib"].versions + if len(__versions) != 1: + print(f"Starting compLib! \033[91mVersion: {__version__} is outdated\033[0m\n" + f"\033[92m[!] run the command 'sudo apt update && sudo apt install python3-complib' to install the newest version\033[0m") + else: + print(f"Starting compLib! \033[92mVersion: {__version__} is up to date\033[0m") + except Exception as e: + compLib.LogstashLogging.Logging.get_logger().error(f"error during checking apt package version -> {str(e)}") + print(f"\033[91merror during checking apt package version -> {str(e)}\033[0m\n") +else: + print("apt is not installed! This is for local development only!") + +if spi_found: + import compLib.Spi + import compLib.Reset + import compLib.Encoder + import logging + + print(f"\033[34mInitializing chipmunk board...\033[0m") + compLib.Reset.Reset.reset_bot() + compLib.Spi.Spi.health_check() + compLib.Spi.Spi.start_health_check_loop() + compLib.Encoder.Encoder.clear_all() + print(f"\033[34mReady\033[0m\n") +else: + print("spidev is not installed! This is for local development only!")