From 5e275a958ba49af16683129cfb58a7606353306d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ebbe=20Ba=C3=9F?= Date: Sun, 18 Feb 2024 17:00:46 +0100 Subject: [PATCH] wasnt helpful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ebbe Baß --- client/main.py | 127 +++++++++++++++++------- server/app.py | 259 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 271 insertions(+), 115 deletions(-) diff --git a/client/main.py b/client/main.py index f1b6cc5..fc8f7f5 100644 --- a/client/main.py +++ b/client/main.py @@ -1,43 +1,98 @@ -_D='message' -_C='success' -_B='192.168.0.1' -_A=None -import subprocess,neopixel,requests,time,paho.mqtt.client as mqtt +import subprocess +import neopixel +import requests +import time +import paho.mqtt.client as mqtt from getmac import get_mac_address import board -SERVER_IP=_B -SERVER_PORT=5000 -wlan_mac_address=str(get_mac_address(interface='wlan0')) -LED_STRIP_PIN=board.D18 + +SERVER_IP = '192.168.0.1' +SERVER_PORT = 5000 + +# Dynamically obtain the MAC address of the WLAN interface +wlan_mac_address = str(get_mac_address(interface="wlan0")) + +# Replace with the GPIO pin connected to the data input of the WS2812B LED strip +LED_STRIP_PIN = board.D18 global LED_COUNT -LED_COUNT=30 +LED_COUNT = 30 global LEDS_PER_PIXEL -LEDS_PER_PIXEL=5 +LEDS_PER_PIXEL = 5 + +# Global variables for LED strip control global strip -strip=neopixel.NeoPixel(pin=board.D18,n=LED_COUNT,auto_write=True) +strip = neopixel.NeoPixel(pin = board.D18, n = LED_COUNT, auto_write = True) + def register_tube(): - try: - response=requests.post(f"http://{SERVER_IP}:{SERVER_PORT}/register_tube",data={'mac_address':wlan_mac_address});print(response);data=response.json() - if data.get(_C):print('Tube registered successfully.') - else:print(f"Registration failed: {data.get(_D)}") - except requests.RequestException as e:print(f"Registration failed: {e}") + # Register or reauthenticate the tube with the server + try: + response = requests.post(f'http://{SERVER_IP}:{SERVER_PORT}/register_tube', data={'mac_address': wlan_mac_address}) + print(response) + data = response.json() + if data.get('success'): + print('Tube registered successfully.') + else: + print(f'Registration failed: {data.get("message")}') + except requests.RequestException as e: + print(f'Registration failed: {e}') + def get_assigned_params(): - try: - response=requests.get(f"http://{SERVER_IP}:{SERVER_PORT}/get_assigned_params/{wlan_mac_address}");data=response.json() - if data.get(_C):return data.get('universe'),data.get('dmx_address') - else:print(f"Failed to fetch assigned parameters: {data.get(_D)}");return _A,_A - except requests.RequestException as e:print(f"Failed to fetch assigned parameters: {e}");return _A,_A -def is_connected_to_wifi():output=subprocess.check_output(['iwgetid']).decode();return output.split('"')[1] -def update_led_strip(rgb_values,pixel,strip):strip[int(pixel)]=rgb_values -def on_message(mqttc,obj,msg):global rgb_values_list;rgb_values_list=eval(msg.payload.decode()) -if __name__=='__main__': - if is_connected_to_wifi()is not _A: - register_tube();time.sleep(1);mqttc=mqtt.Client(mqtt.CallbackAPIVersion.VERSION2);mqttc.connect(_B,1883,60);mqttc.on_message=on_message;mqttc.subscribe('tube-'+str(wlan_mac_address)+'/pixel_colors',0);global rgb_values_list;rgb_values_list=eval("['[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]']");mqttc.loop_start() - while True: - for pixel in range(LEDS_PER_PIXEL):update_led_strip(tuple(eval(rgb_values_list[0])),pixel,strip) - for pixel in range(LEDS_PER_PIXEL,LEDS_PER_PIXEL*2):update_led_strip(tuple(eval(rgb_values_list[1])),pixel,strip) - for pixel in range(LEDS_PER_PIXEL*2,LEDS_PER_PIXEL*3):update_led_strip(tuple(eval(rgb_values_list[2])),pixel,strip) - for pixel in range(LEDS_PER_PIXEL*3,LEDS_PER_PIXEL*4):update_led_strip(tuple(eval(rgb_values_list[3])),pixel,strip) - for pixel in range(LEDS_PER_PIXEL*4,LEDS_PER_PIXEL*5):update_led_strip(tuple(eval(rgb_values_list[4])),pixel,strip) - for pixel in range(LEDS_PER_PIXEL*5,LEDS_PER_PIXEL*6):update_led_strip(tuple(eval(rgb_values_list[5])),pixel,strip) - time.sleep(.5) \ No newline at end of file + try: + response = requests.get(f'http://{SERVER_IP}:{SERVER_PORT}/get_assigned_params/{wlan_mac_address}') + data = response.json() + if data.get('success'): + return data.get('universe'), data.get('dmx_address') + else: + print(f'Failed to fetch assigned parameters: {data.get("message")}') + return None, None + except requests.RequestException as e: + print(f'Failed to fetch assigned parameters: {e}') + return None, None + +def is_connected_to_wifi(): + output = subprocess.check_output(['iwgetid']).decode() + return output.split('"')[1] + +def update_led_strip(rgb_values, pixel, strip): + strip[int(pixel)] = rgb_values + +def on_message(mqttc, obj, msg): + global rgb_values_list + rgb_values_list = eval(msg.payload.decode()) + +if __name__ == "__main__": + # Connect to Wi-Fi + if is_connected_to_wifi() is not None: + # Register/reauthenticate the tube + register_tube() + time.sleep(1) + + mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + mqttc.connect("192.168.0.1", 1883, 60) + mqttc.on_message = on_message + mqttc.subscribe("tube-"+str(wlan_mac_address)+"/pixel_colors", 0) + + global rgb_values_list + rgb_values_list = eval("['[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]', '[0, 0, 0]']") + + mqttc.loop_start() + while True: + for pixel in range(LEDS_PER_PIXEL): + update_led_strip(tuple(eval(rgb_values_list[0])), pixel, strip) + + for pixel in range(LEDS_PER_PIXEL, LEDS_PER_PIXEL*2): + update_led_strip(tuple(eval(rgb_values_list[1])), pixel, strip) + + for pixel in range(LEDS_PER_PIXEL*2, LEDS_PER_PIXEL*3): + update_led_strip(tuple(eval(rgb_values_list[2])), pixel, strip) + + for pixel in range(LEDS_PER_PIXEL*3, LEDS_PER_PIXEL*4): + update_led_strip(tuple(eval(rgb_values_list[3])), pixel, strip) + + for pixel in range(LEDS_PER_PIXEL*4, LEDS_PER_PIXEL*5): + update_led_strip(tuple(eval(rgb_values_list[4])), pixel, strip) + + for pixel in range(LEDS_PER_PIXEL*5, LEDS_PER_PIXEL*6): + update_led_strip(tuple(eval(rgb_values_list[5])), pixel, strip) + + time.sleep(0.5) \ No newline at end of file diff --git a/server/app.py b/server/app.py index 4758a73..af284c8 100644 --- a/server/app.py +++ b/server/app.py @@ -1,81 +1,182 @@ -V='localhost' -U='password' -T='user' -S='host' -R='config.json' -Q=Exception -N='message' -M='database' -I='success' -H=int -G=print -B='mysql' -D=True -C=str -from flask import Flask,request as W,jsonify as E -import json as O -from MySQLdb import connect as X -import paho.mqtt.client as P,python_artnet as l,os -from getmac import get_mac_address as Y -import time,sys -from multiprocessing import Process as J,Pipe -from ast import literal_eval as b -K=Flask(__name__) -Z=C(Y(interface='wlan0')) +from flask import Flask, request, jsonify +import json +from MySQLdb import connect +import paho.mqtt.client as mqtt +import python_artnet as Artnet +import os +from getmac import get_mac_address +import time +import sys +from multiprocessing import Process, Pipe +from ast import literal_eval + +app = Flask(__name__) + +wlan_mac_address = str(get_mac_address(interface="wlan0")) + +# Read configuration from config.json try: - with open(R,'r')as L:A=O.load(L) + with open('config.json', 'r') as config_file: + config = json.load(config_file) except FileNotFoundError: - A={B:{S:V,T:'pxm',U:'pixel',M:'pixeltube_db'}} - with open(R,'w')as L:O.dump(A,L,indent=4) -o=A[B][M] -F=X(host=A[B][S],user=A[B][T],password=A[B][U],database=A[B][M]) -F.autocommit(D) -p='PiXelTubeMaster-'+Z -def a(mac_address): - B=mac_address;A=F.cursor();A.execute('SELECT * FROM tubes WHERE mac_address = %s',(B,));C=A.fetchone() - if not C:A.execute('INSERT INTO tubes (mac_address, universe, dmx_address) VALUES (%s, %s, %s)',(B,0,1)) - else:0 - A.close() -@K.route('/register_tube',methods=['POST']) -def q():A=W.form.get('mac_address');a(C(A));return E({I:D,N:'Tube registered successfully.'}) -@K.route('/get_assigned_params/',methods=['GET']) -def r(tube_unique_id): - C=False - try: - A=F.cursor();A.execute('SELECT universe, dmx_address FROM tubes WHERE mac_address = %s',(tube_unique_id,));B=A.fetchone();A.close() - if B:G,H=B;return E({I:D,'universe':G,'dmx_address':H}) - else:return E({I:C,N:'Tube not found in the database'}) - except Q as J:return E({I:C,N:f"Error: {J}"}) -def c():K.run(host='192.168.0.1',port=5000) -def m(): - try:A=C(os.system("ip -4 -o addr show eth0 | awk '{print $4}' | cut -d '/' -f 1 "));return A - except(KeyError,IndexError,OSError)as B:G(f"Error getting eth0 IP: {B}");exit -def d(client,userdata,flags,reason_code,properties): - A=reason_code - if A==0:G('Connected to MQTT Broker!') - else:G('Failed to connect, return code %d\n',C(A)) -def n():A=P.Client(P.CallbackAPIVersion.VERSION2);A.on_connect=d;A.connect(V,1883);return A -def e(ti_receiver): - k='/pixel_colors';j='tube-';i='PiXelTubeMaster';c=ti_receiver;G=None;d=n();o=m();e=l.Artnet(BINDIP=o,DEBUG=D,SHORTNAME=i,LONGNAME=i,PORT=6454) - while D: - try: - F=e.readPacket() - if c.poll(): - f=c.recv();g,h=b(f),b(f) - if F is not G: - A=F.data - if g is not G: - for E in g: - if F.universe==H(E[1]):B=H(E[2]);I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=A[B],A[B+1],A[B+2],A[B+3],A[B+4],A[B+5],A[B+6],A[B+7],A[B+8],A[B+9],A[B+10],A[B+11],A[B+12],A[B+13],A[B+14],A[B+15],A[B+16],A[B+17];a=j+C(E[0])+k;d.publish(a,C([C([K,I,J]),C([N,L,M]),C([Q,O,P]),C([T,R,S]),C([W,U,V]),C([Z,X,Y])])) - elif F is not G: - A=F.data - if h is not G: - for E in h: - if F.universe==H(E[1]):B=H(E[2]);I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=A[B],A[B+1],A[B+2],A[B+3],A[B+4],A[B+5],A[B+6],A[B+7],A[B+8],A[B+9],A[B+10],A[B+11],A[B+12],A[B+13],A[B+14],A[B+15],A[B+16],A[B+17];a=j+C(E[0])+k;d.publish(a,C([C([K,I,J]),C([N,L,M]),C([Q,O,P]),C([T,R,S]),C([W,U,V]),C([Z,X,Y])])) - except KeyboardInterrupt:e.close();sys.exit() -def f(ti_sender): - while D: - try:A=F.cursor();A.execute('SELECT mac_address, universe, dmx_address FROM tubes');B=A.fetchall();A.close();ti_sender.send(C(B)) - except Q as E:G(E) - time.sleep(2) -if __name__=='__main__':g,h=Pipe(D);i=J(target=f,args=(h,));i.start();j=J(target=e,args=(g,));j.start();k=J(target=c);k.start() \ No newline at end of file + # Create config.json with default values if it doesn't exist + config = { + "mysql": { + "host": "localhost", + "user": "pxm", + "password": "pixel", + "database": "pixeltube_db" + }, + } + with open('config.json', 'w') as config_file: + json.dump(config, config_file, indent=4) + +database = config['mysql']['database'] + +db = connect( + host=config['mysql']['host'], + user=config['mysql']['user'], + password=config['mysql']['password'], + database=config['mysql']['database'], +) + +db.autocommit(True) + +mqtt_client_id = "PiXelTubeMaster-"+wlan_mac_address + +# Function to register a tube in the database +def register_tube(mac_address): + cur1 = db.cursor() + # Check if the tube already exists in the database + cur1.execute("SELECT * FROM tubes WHERE mac_address = %s", (mac_address,)) + existing_tube = cur1.fetchone() + + # Check if the tube exsist. If it doesn't create a new db row + if not existing_tube: + cur1.execute("INSERT INTO tubes (mac_address, universe, dmx_address) VALUES (%s, %s, %s)", + (mac_address, 0, 1)) + else: + pass + cur1.close() + +# Registration system route +@app.route('/register_tube', methods=['POST']) +def register_tube_route(): + mac_address = request.form.get('mac_address') + register_tube(str(mac_address)) + return jsonify({'success': True, 'message': 'Tube registered successfully.'}) + + +@app.route('/get_assigned_params/', methods=['GET']) +def get_assigned_params(tube_unique_id): + try: + cur = db.cursor() + cur.execute("SELECT universe, dmx_address FROM tubes WHERE mac_address = %s", (tube_unique_id,)) + result = cur.fetchone() + cur.close() + + if result: + universe, dmx_address = result + return jsonify({'success': True, 'universe': universe, 'dmx_address': dmx_address}) + else: + return jsonify({'success': False, 'message': 'Tube not found in the database'}) + except Exception as e: + return jsonify({'success': False, 'message': f'Error: {e}'}) + +def flask_api(): + app.run(host='192.168.0.1', port=5000) + +def get_eth0_ip(): + try: + # Get the IP address of the eth0 interface + eth0_ip = str(os.system("ip -4 -o addr show eth0 | awk '{print $4}' | cut -d '/' -f 1 ")) + return eth0_ip + except (KeyError, IndexError, OSError) as e: + print(f"Error getting eth0 IP: {e}") + exit + +def on_connect(client, userdata, flags, reason_code, properties): + if reason_code == 0: + print("Connected to MQTT Broker!") + else: + print("Failed to connect, return code %d\n", str(reason_code)) + +def connect_mqtt(): + # Set Connecting Client ID + client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + # client.username_pw_set(username, password) + client.on_connect = on_connect + client.connect("localhost", 1883) + return client + +def mqtt_publisher(ti_receiver): + # Create and start a thread for each universe + mqtt_client = connect_mqtt() + artnetBindIp = get_eth0_ip() + artNet = Artnet.Artnet(BINDIP = artnetBindIp, DEBUG = True, SHORTNAME = "PiXelTubeMaster", LONGNAME = "PiXelTubeMaster", PORT = 6454) + while True: + try: + # Gets whatever the last Art-Net packet we received is + artNetPacket = artNet.readPacket() + # Make sure we actually *have* a packet + if ti_receiver.poll(): + ti_data = ti_receiver.recv() + tube_index, tube_index_old = literal_eval(ti_data), literal_eval(ti_data) + if artNetPacket is not None: + #Checks to see if the current packet is for the specified DMX Universe + dmxPacket = artNetPacket.data + # Create MQTT topic based on the universe and channel + if tube_index is not None: + for index_row in tube_index: + if artNetPacket.universe == int(index_row[1]): + dmx_address = int(index_row[2]) + #Define RGB values per pixel + p1_g, p1_b, p1_r, p2_g, p2_b, p2_r, p3_g, p3_b, p3_r, p4_g, p4_b, p4_r, p5_g, p5_b, p5_r, p6_g, p6_b, p6_r = dmxPacket[dmx_address], dmxPacket[dmx_address+1], dmxPacket[dmx_address+2], dmxPacket[dmx_address+3], dmxPacket[dmx_address+4], dmxPacket[dmx_address+5], dmxPacket[dmx_address+6], dmxPacket[dmx_address+7], dmxPacket[dmx_address+8], dmxPacket[dmx_address+9], dmxPacket[dmx_address+10], dmxPacket[dmx_address+11], dmxPacket[dmx_address+12], dmxPacket[dmx_address+13], dmxPacket[dmx_address+14], dmxPacket[dmx_address+15], dmxPacket[dmx_address+16], dmxPacket[dmx_address+17] + + # Pixel topics + p1_topic = "tube-"+str(index_row[0])+"/pixel_colors" + + # Publish pixel topic + mqtt_client.publish(p1_topic, str([str([p1_r, p1_g, p1_b]), str([p2_r, p2_g, p2_b]), str([p3_r, p3_g, p3_b]), str([p4_r, p4_g, p4_b]), str([p5_r, p5_g, p5_b]), str([p6_r, p6_g, p6_b])])) + else: + if artNetPacket is not None: + #Checks to see if the current packet is for the specified DMX Universe + dmxPacket = artNetPacket.data + # Create MQTT topic based on the universe and channel + if tube_index_old is not None: + for index_row in tube_index_old: + if artNetPacket.universe == int(index_row[1]): + dmx_address = int(index_row[2]) + #Define RGB values per pixel + p1_g, p1_b, p1_r, p2_g, p2_b, p2_r, p3_g, p3_b, p3_r, p4_g, p4_b, p4_r, p5_g, p5_b, p5_r, p6_g, p6_b, p6_r = dmxPacket[dmx_address], dmxPacket[dmx_address+1], dmxPacket[dmx_address+2], dmxPacket[dmx_address+3], dmxPacket[dmx_address+4], dmxPacket[dmx_address+5], dmxPacket[dmx_address+6], dmxPacket[dmx_address+7], dmxPacket[dmx_address+8], dmxPacket[dmx_address+9], dmxPacket[dmx_address+10], dmxPacket[dmx_address+11], dmxPacket[dmx_address+12], dmxPacket[dmx_address+13], dmxPacket[dmx_address+14], dmxPacket[dmx_address+15], dmxPacket[dmx_address+16], dmxPacket[dmx_address+17] + + # Pixel topics + p1_topic = "tube-"+str(index_row[0])+"/pixel_colors" + + # Publish pixel topic + mqtt_client.publish(p1_topic, str([str([p1_r, p1_g, p1_b]), str([p2_r, p2_g, p2_b]), str([p3_r, p3_g, p3_b]), str([p4_r, p4_g, p4_b]), str([p5_r, p5_g, p5_b]), str([p6_r, p6_g, p6_b])])) + except KeyboardInterrupt: + artNet.close() + sys.exit() + +def tube_index_updater(ti_sender): + while True: + try: + cur = db.cursor() + cur.execute("SELECT mac_address, universe, dmx_address FROM tubes") + tube_index = cur.fetchall() + cur.close() + ti_sender.send(str(tube_index)) + # print("Updated tube index with values: "+str(tube_index)) + except Exception as e: + print(e) + time.sleep(2) + +if __name__ == "__main__": + (ti_receiver,ti_sender) = Pipe(True) + ti_updater_thread = Process(target=tube_index_updater, args=(ti_sender, )) + ti_updater_thread.start() + publisher_thread = Process(target=mqtt_publisher, args=(ti_receiver, )) + publisher_thread.start() + flask_thread = Process(target=flask_api) + flask_thread.start() \ No newline at end of file