diff --git a/Drivers/button_control/button_control.py b/Drivers/button_control/button_control.py new file mode 100644 index 00000000..fdece781 --- /dev/null +++ b/Drivers/button_control/button_control.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +""" +Renamed folder & file +Move onto Pi +Delete old files +give permissions to new files +""" + +import os +import sys +import paho.mqtt.client as mqtt +import RPi.GPIO as GPIO +import time +import json +from argparse import ArgumentParser +import logging + +# append this file's directory to path +root_folder = os.path.abspath(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +sys.path.append(root_folder) + +from lib.mqtt_client import MQTTClient + +# set up logging +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +logger_formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s') + +logger_file_handler = logging.FileHandler('turning_control.log') # TODO: setup a logging folder and write all logging files to that folder +logger_file_handler.setFormatter(logger_formatter) + +logger_stream_handler = logging.StreamHandler() # this will print all logs to the terminal also + +logger.addHandler(logger_file_handler) +logger.addHandler(logger_stream_handler) + +# define pins +RIGHT_PIN = 11 +LEFT_PIN = 12 +BREAK_PIN = 15 + +# get MQTT credentials from passed values +parser = ArgumentParser(description="Bike turning controller") +parser.add_argument('--broker_address', dest='broker_address', default=os.getenv('MQTT_HOSTNAME'), type=str, help='The MQTT broker address getting from HiveMQ Cloud') +parser.add_argument('--username', dest='username', default=os.getenv('MQTT_USERNAME'), type=str, help='MQTT username') +parser.add_argument('--password', dest='password', default=os.getenv('MQTT_PASSWORD'), type=str, help='MQTT password') +parser.add_argument('--port', dest='port', default=os.getenv('MQTT_PORT'), type=int, help='MQTT broker port') +parser.add_argument('--device_id', dest='device_id', default=os.getenv('DEVICE_ID'), type=str, help="Bike's unique id") +parser.add_argument('--button_topic', dest='button_topic', default=f"bike/{os.getenv('DEVICE_ID')}/button", help='MQTT topic for activity of the buttons on the bike') +args = parser.parse_args() + +class Button(): + + def __init__(self, pin: int, name: str, client: MQTTClient): + + # define properties + self._pin = pin + self._name = name + self._client = client + self._state = 0 + self._topic = args.button_topic + self._control_topic = args.button_topic + '/report' + + # set up pin & callbacks + GPIO.setup(self._pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) + GPIO.add_event_detect(self._pin, GPIO.BOTH, callback=self.state_change, bouncetime=200) + + logger.info(f'initialised {self._name} button') + + def state_change(self, pin: int): + """the callback passes the pin for some reason.""" + # grab the current state + self._state = GPIO.input(self._pin) + + # publish to MQTT + payload = json.dumps({'button' : self._name, 'state' : self._state, 'timestamp' : time.time()}) + self._client.publish(self._control_topic, payload) + + # log the change + if self._state == 0: + logger.debug(f'{self._name} button released') + elif self._state == 1: + logger.debug(f'{self._name} button pressed') + +def main(): + # set up MQTT client + client = MQTTClient(args.broker_address, args.username, args.password, port=args.port) + client.setup_mqtt_client() + + # set up GPIO + GPIO.setmode(GPIO.BOARD) + + # create buttons + left_button = Button(LEFT_PIN, 'LEFT', client) + right_button = Button(RIGHT_PIN, 'RIGHT', client) + break_button = Button(BREAK_PIN, 'BREAK', client) + + # loop until terminated + # TODO: is this actually ok to do? + try: + while True: + pass + + except KeyboardInterrupt: + GPIO.cleanup() + #client.disconnect() + +if __name__=="__main__": + main() \ No newline at end of file diff --git a/Drivers/lib/__init__.py b/Drivers/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Drivers/lib/mqtt_client.py b/Drivers/lib/mqtt_client.py index f62b7213..80fd5bb1 100755 --- a/Drivers/lib/mqtt_client.py +++ b/Drivers/lib/mqtt_client.py @@ -3,13 +3,30 @@ import time import paho.mqtt.client as paho from paho import mqtt +import logging + +# setup logging + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +logger_formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s') + +logger_file_handler = logging.FileHandler('mqtt.log') # TODO: setup a logging folder and write all logging files to that folder +logger_file_handler.setFormatter(logger_formatter) + +logger_stream_handler = logging.StreamHandler() # this will print all logs to the terminal also + +logger.addHandler(logger_file_handler) +logger.addHandler(logger_stream_handler) # this is a MQTT client that is able to publish to and subscribe from MQTT topics in HiveMQ Cloud class MQTTClient: - def __init__(self, broker_address, username, password): + def __init__(self, broker_address, username, password, port=1883): self.broker_address = broker_address self.username = username self.password = password + self.port = port self.client = None def get_client(self): @@ -23,11 +40,11 @@ def setup_mqtt_client(self): self.client.on_connect = self.on_connect # enable TLS for secure connection - self.client.tls_set(tls_version=mqtt.client.ssl.PROTOCOL_TLS) + self.client.tls_set(tls_version=paho.ssl.PROTOCOL_TLS) # set username and password self.client.username_pw_set(self.username, self.password) # connect to HiveMQ Cloud on port 8883 (default for MQTT) - self.client.connect(self.broker_address, 8883) + self.client.connect(self.broker_address, self.port) # setting callbacks, use separate functions like above for better visibility self.client.on_subscribe = self.on_subscribe @@ -54,20 +71,20 @@ def loop_start(self): # setting callbacks for different events to see if it works, print the message etc. def on_connect(self, client, userdata, flags, rc, properties=None): - print("CONNACK received with code %s." % rc) + logger.info("CONNACK received with code %s." % rc) # with this callback you can see if your publish was successful def on_publish(self, client, userdata, mid, properties=None): - print("[MQTT message published] mid: " + str(mid)) + logger.info("[MQTT message published] mid: " + str(mid)) # print which topic was subscribed to def on_subscribe(self, client, userdata, mid, granted_qos, properties=None): - print("Subscribed: " + str(mid) + " " + str(granted_qos)) + logger.info("Subscribed: " + str(mid) + " " + str(granted_qos)) # print message, useful for checking if it was successful def on_message(self, client, userdata, msg): - print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload)) + logger.info(msg.topic + " " + str(msg.qos) + " " + str(msg.payload)) def on_disconnect(self, client, userdata,rc=0): self.client.logging.debug(f"Disconnected result code: {str(rc)}") - self.client.loop_stop() \ No newline at end of file + self.client.loop_stop() diff --git a/Drivers/pico_remote/readme.md b/Drivers/pico_remote/readme.md index e69de29b..91f94506 100644 --- a/Drivers/pico_remote/readme.md +++ b/Drivers/pico_remote/readme.md @@ -0,0 +1,25 @@ +# Description: +This device interacts with the wahoo kickr and climbr via the Raspberry Pi 000001, located in the IoT lab, building M.102. +Its intention is to manipulate the hardware in real-time without the need for running or accessing third-party software such as the mobile app, VR, or other interfaces. +The purpose of this is that it allows users to simply use the bike with a simple interface. + +# How to Run: +- Kickr script (/iot/scripts/./start_kickr.sh) must be executed and successful connection between Pi and Kickr must be established for this device to work as intended. +- Turn on remote device by pushing the white button on the power regulator on the top of the breadboard +- BT module should be flashing red while waiting for pairing. +- Navigate to iot/Drivers/pico_remote and execute the script via 'python3 pico_bt_handler.py' to run the handler. +- successful connection is determined by the HC-06 module turning into a solid red light. +- Upon successful connection between the HC-06 Bluetooth module and the Raspberry pi, you may now interact with the hardware via the push buttons: + +### Note: You must press and hold the selected button in order to influence hardware. + +# Buttons: +### Button 1: increase resistance +### Button 2: decrease resistance +### Button 3: increase incline +### Button 4: decrease incline + +![Screenshot 2023-09-24 142627](https://github.com/redbackoperations/iot/assets/69894063/d3f90db2-0b68-41e7-b8c1-3ca8d65c8ad4) +![WIN_20230924_12_03_43_Pro](https://github.com/redbackoperations/iot/assets/69894063/0cd708ff-146f-48b0-ac11-f858ef215387) +![WIN_20230924_12_03_08_Pro](https://github.com/redbackoperations/iot/assets/69894063/91f63b5b-432b-4208-a054-40ffb96bd527) + diff --git a/scripts/start_button_control.sh b/scripts/start_button_control.sh new file mode 100644 index 00000000..53b31476 --- /dev/null +++ b/scripts/start_button_control.sh @@ -0,0 +1,3 @@ +source ~/.env + +python3 ~/iot/Drivers/button_control/button_control.py \ No newline at end of file