Initial Arduino UNO Q template with LED Matrix functionality
- Complete MPU-MCU communication setup - LED Matrix text display with configurable parameters - Configuration management with personal data protection - Git template with .gitignore for sensitive data - Automated build and deployment scripts - SSH key management and service scripts
This commit is contained in:
1
lib/__init__.py
Normal file
1
lib/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Arduino UNOQ Library
|
||||
1
lib/arduino_unoq/__init__.py
Normal file
1
lib/arduino_unoq/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Arduino UNOQ Library
|
||||
176
lib/arduino_unoq/bridge.py
Normal file
176
lib/arduino_unoq/bridge.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""
|
||||
Arduino UNO Q Library
|
||||
Bridge communication between MPU (Linux) and MCU (STM32)
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ArduinoUNOQ:
|
||||
"""Arduino UNO Q Bridge Communication Class"""
|
||||
|
||||
def __init__(self):
|
||||
self.bridge_available = False
|
||||
self.setup_bridge()
|
||||
|
||||
def setup_bridge(self):
|
||||
"""Setup Arduino Bridge communication"""
|
||||
try:
|
||||
# Try to import Arduino Bridge library
|
||||
sys.path.append('/usr/lib/python3/dist-packages')
|
||||
# Note: Uncomment when Bridge library is available
|
||||
# import bridge
|
||||
# self.bridge = bridge.Bridge()
|
||||
# self.bridge_available = True
|
||||
logger.info("Arduino Bridge simulation mode (library not available)")
|
||||
self.bridge_available = False
|
||||
except ImportError:
|
||||
logger.warning("Arduino Bridge not available, running in simulation mode")
|
||||
self.bridge_available = False
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize Bridge: {e}")
|
||||
self.bridge_available = False
|
||||
|
||||
def read_mcu_data(self):
|
||||
"""Read data from MCU via Bridge"""
|
||||
# TODO: Implement your MCU data reading logic here
|
||||
if not self.bridge_available:
|
||||
return {"status": "simulated", "message": "Bridge not available"}
|
||||
|
||||
try:
|
||||
# Example: Read digital pins
|
||||
data = {}
|
||||
# TODO: Add your pin reading logic
|
||||
# for pin in range(2, 14):
|
||||
# value = self.bridge.digitalRead(pin)
|
||||
# data[f"d{pin}"] = value
|
||||
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.error(f"Error reading MCU data: {e}")
|
||||
return {}
|
||||
|
||||
def write_mcu_pin(self, pin, value):
|
||||
"""Write to MCU pin via Bridge"""
|
||||
# TODO: Implement your MCU pin writing logic here
|
||||
if not self.bridge_available:
|
||||
logger.info(f"Simulated: Pin {pin} set to {value}")
|
||||
return True
|
||||
|
||||
try:
|
||||
if isinstance(value, str) and value.lower() in ['high', 'low']:
|
||||
value = 1 if value.lower() == 'high' else 0
|
||||
|
||||
# TODO: Add your pin writing logic
|
||||
# self.bridge.digitalWrite(pin, value)
|
||||
logger.info(f"Pin {pin} set to {value}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error writing to pin {pin}: {e}")
|
||||
return False
|
||||
|
||||
def send_led_matrix_command(self, text, speed=150, display_time=5000, direction=0):
|
||||
"""Send LED Matrix command to MCU"""
|
||||
command = f'"{text}",{speed},{display_time},{direction}'
|
||||
|
||||
if not self.bridge_available:
|
||||
logger.info(f"Simulated LED Matrix command: {command}")
|
||||
return True
|
||||
|
||||
try:
|
||||
# Send command via serial to MCU
|
||||
# This would use actual Bridge serial communication
|
||||
# self.bridge.serial.write(command.encode())
|
||||
logger.info(f"LED Matrix command sent: {command}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending LED Matrix command: {e}")
|
||||
return False
|
||||
|
||||
def process_command(self, command):
|
||||
"""Process commands from external interface"""
|
||||
try:
|
||||
cmd_data = json.loads(command)
|
||||
cmd_type = cmd_data.get('type')
|
||||
|
||||
if cmd_type == 'read':
|
||||
return self.read_mcu_data()
|
||||
elif cmd_type == 'write':
|
||||
pin = cmd_data.get('pin')
|
||||
value = cmd_data.get('value')
|
||||
return {"success": self.write_mcu_pin(pin, value)}
|
||||
elif cmd_type == 'led_matrix':
|
||||
text = cmd_data.get('text', 'Hallo World')
|
||||
speed = cmd_data.get('speed', 150)
|
||||
display_time = cmd_data.get('time', 5000)
|
||||
direction = cmd_data.get('direction', 0)
|
||||
return {"success": self.send_led_matrix_command(text, speed, display_time, direction)}
|
||||
elif cmd_type == 'status':
|
||||
return {
|
||||
"bridge_available": self.bridge_available,
|
||||
"uptime": time.time(),
|
||||
"status": "running"
|
||||
}
|
||||
else:
|
||||
return {"error": "Unknown command type"}
|
||||
|
||||
except json.JSONDecodeError:
|
||||
return {"error": "Invalid JSON command"}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
def main_loop(self):
|
||||
"""Main application loop"""
|
||||
logger.info("Arduino UNO Q MPU Application Started")
|
||||
|
||||
# Create command pipe for external communication
|
||||
cmd_pipe = Path('/tmp/unoq_cmd.pipe')
|
||||
status_file = Path('/tmp/unoq_status.json')
|
||||
|
||||
try:
|
||||
# Create named pipe if it doesn't exist
|
||||
if not cmd_pipe.exists():
|
||||
os.mkfifo(cmd_pipe)
|
||||
except:
|
||||
pass
|
||||
|
||||
while True:
|
||||
try:
|
||||
# TODO: Add your main application logic here
|
||||
|
||||
# Check for commands
|
||||
if cmd_pipe.exists():
|
||||
try:
|
||||
with open(str(cmd_pipe), 'r') as f:
|
||||
command = f.read().strip()
|
||||
if command:
|
||||
result = self.process_command(command)
|
||||
|
||||
# Write result to status file
|
||||
with open(str(status_file), 'w') as f:
|
||||
json.dump(result, f)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Periodic status update
|
||||
current_data = self.read_mcu_data()
|
||||
current_data["timestamp"] = str(int(time.time()))
|
||||
current_data["status"] = "running"
|
||||
|
||||
with open(str(status_file), 'w') as f:
|
||||
json.dump(current_data, f)
|
||||
|
||||
time.sleep(1) # Update every second
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Shutting down...")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"Error in main loop: {e}")
|
||||
time.sleep(5) # Wait before retrying
|
||||
81
lib/config_loader.py
Normal file
81
lib/config_loader.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Configuration loader for Arduino UNO Q project
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
class Config:
|
||||
def __init__(self, config_file="config.json"):
|
||||
self.config_file = Path(config_file)
|
||||
self.config = self.load_config()
|
||||
|
||||
def load_config(self):
|
||||
"""Load configuration from JSON file"""
|
||||
if not self.config_file.exists():
|
||||
# Try to copy from example
|
||||
example_file = Path("config.example.json")
|
||||
if example_file.exists():
|
||||
print(f"Creating config from example: {self.config_file}")
|
||||
import shutil
|
||||
shutil.copy(example_file, self.config_file)
|
||||
print("Please edit config.json with your personal settings")
|
||||
else:
|
||||
raise FileNotFoundError(f"Config file {self.config_file} not found")
|
||||
|
||||
try:
|
||||
with open(self.config_file, 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
# Expand paths
|
||||
self.expand_paths(config)
|
||||
return config
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON in config file: {e}")
|
||||
|
||||
def expand_paths(self, config):
|
||||
"""Expand ~ and relative paths"""
|
||||
if 'arduino_uno_q' in config and 'ssh_key' in config['arduino_uno_q']:
|
||||
ssh_key = config['arduino_uno_q']['ssh_key']
|
||||
if ssh_key.startswith('~'):
|
||||
config['arduino_uno_q']['ssh_key'] = str(Path.home() / ssh_key[1:])
|
||||
|
||||
if 'paths' in config:
|
||||
for key, path in config['paths'].items():
|
||||
if isinstance(path, str) and path.startswith('~'):
|
||||
config['paths'][key] = str(Path.home() / path[1:])
|
||||
|
||||
def get(self, key_path, default=None):
|
||||
"""Get configuration value by dot notation"""
|
||||
keys = key_path.split('.')
|
||||
value = self.config
|
||||
|
||||
for key in keys:
|
||||
if isinstance(value, dict) and key in value:
|
||||
value = value[key]
|
||||
else:
|
||||
return default
|
||||
|
||||
return value
|
||||
|
||||
def get_arduino_config(self):
|
||||
"""Get Arduino UNO Q connection configuration"""
|
||||
return self.get('arduino_uno_q', {})
|
||||
|
||||
def get_build_config(self):
|
||||
"""Get build configuration"""
|
||||
return self.get('build', {})
|
||||
|
||||
def get_paths(self):
|
||||
"""Get paths configuration"""
|
||||
return self.get('paths', {})
|
||||
|
||||
def get_led_matrix_config(self):
|
||||
"""Get LED Matrix configuration"""
|
||||
return self.get('led_matrix', {})
|
||||
|
||||
# Global config instance
|
||||
config = Config()
|
||||
Reference in New Issue
Block a user