diff --git a/build.sh b/build.sh index 43267df..5806614 100755 --- a/build.sh +++ b/build.sh @@ -13,6 +13,10 @@ if ! ./tools/verify-versions.sh; then exit 1 fi +echo "Setting up web interface structure..." +mkdir -p gecko_controller/web/templates +[ ! -f gecko_controller/web/__init__.py ] && touch gecko_controller/web/__init__.py + echo "Building Debian package..." if ! dpkg-buildpackage -us -uc; then echo "Error: Package build failed" @@ -21,4 +25,14 @@ fi echo "Build completed successfully!" echo "Package files created in parent directory:" -ls -l ../*.deb ../*.buildinfo ../*.changes \ No newline at end of file +ls -l ../*.deb ../*.buildinfo ../*.changes + +echo +echo "Next steps:" +echo "1. Install the package: sudo dpkg -i ../gecko-controller_*.deb" +echo "2. Install dependencies: sudo apt-get install -f" +echo "3. Start the web interface: sudo systemctl start gecko-web" +echo "4. Enable web interface autostart: sudo systemctl enable gecko-web" +echo "5. Check status: sudo systemctl status gecko-web" +echo +echo "The web interface will be available at http://localhost:8080" \ No newline at end of file diff --git a/debian/control b/debian/control index 17408da..b6fae10 100644 --- a/debian/control +++ b/debian/control @@ -13,10 +13,15 @@ Depends: ${python3:Depends}, ${misc:Depends}, python3-pip, python3-venv, - i2c-tools, - python3 (>= 3.9) -Description: Raspberry Pi Gecko Enclosure Controller - Automated temperature and light controller for gecko enclosure - with OLED status display. Monitors temperature and humidity, - controls lighting cycles, manages heating, and displays status - on an OLED screen. \ No newline at end of file + python3 (>= 3.9), + python3-rpi.gpio, + python3-pillow, + python3-smbus, + python3-flask, + i2c-tools +Description: Raspberry Pi Gecko Vivarium Controller + Automated environmental controller for gecko vivarium with OLED status + display. Monitors temperature and humidity, controls day/night lighting + cycles, manages heating, and provides both OLED display and web interface + for status monitoring and configuration. Includes UV monitoring for + optimal basking conditions. \ No newline at end of file diff --git a/debian/gecko-web.service b/debian/gecko-web.service new file mode 100644 index 0000000..c9df684 --- /dev/null +++ b/debian/gecko-web.service @@ -0,0 +1,13 @@ +[Unit] +Description=Gecko Controller Web Interface +After=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/gecko-web +Restart=always +RestartSec=5 +User=root + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/debian/gecko-web.sh b/debian/gecko-web.sh new file mode 100644 index 0000000..53114d5 --- /dev/null +++ b/debian/gecko-web.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec python3 -m gecko_controller.web.app diff --git a/debian/rules b/debian/rules index c706c4a..aa40ea4 100755 --- a/debian/rules +++ b/debian/rules @@ -13,8 +13,10 @@ override_dh_auto_install: mkdir -p debian/gecko-controller/etc/gecko-controller mkdir -p debian/gecko-controller/lib/systemd/system install -m 755 debian/gecko-controller.sh debian/gecko-controller/usr/bin/gecko-controller + install -m 755 debian/gecko-web.sh debian/gecko-controller/usr/bin/gecko-web install -m 644 debian/gecko-controller.service debian/gecko-controller/lib/systemd/system/ + install -m 644 debian/gecko-web.service debian/gecko-controller/lib/systemd/system/ install -m 644 debian/config.py debian/gecko-controller/etc/gecko-controller/ override_dh_auto_test: - : + : \ No newline at end of file diff --git a/gecko_controller/web/__init__.py b/gecko_controller/web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gecko_controller/web/app.py b/gecko_controller/web/app.py new file mode 100755 index 0000000..de076a8 --- /dev/null +++ b/gecko_controller/web/app.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# gecko_controller/web/app.py +from flask import Flask, render_template, jsonify, request +import os +import re +import csv +from datetime import datetime +import pkg_resources + +app = Flask(__name__) +app.template_folder = pkg_resources.resource_filename('gecko_controller.web', 'templates') + +CONFIG_FILE = '/etc/gecko-controller/config.py' +LOG_FILE = '/var/log/gecko-controller/readings.log' + +def read_config(): + """Read and parse the config file""" + config = {} + with open(CONFIG_FILE, 'r') as f: + content = f.read() + # Extract key-value pairs using regex + pairs = re.findall(r'(\w+)\s*=\s*([^#\n]+)', content) + for key, value in pairs: + # Clean up the value + value = value.strip().strip('"\'') + try: + # Try to evaluate as Python literal + import ast + config[key] = ast.literal_eval(value) + except: + # If not a literal, store as string + config[key] = value + return config + +def write_config(config): + """Write config back to file""" + # Read existing file to preserve comments and structure + with open(CONFIG_FILE, 'r') as f: + lines = f.readlines() + + # Update values while preserving structure + new_lines = [] + for line in lines: + if '=' in line and not line.strip().startswith('#'): + key = line.split('=')[0].strip() + if key in config: + value = config[key] + if isinstance(value, str) and not key.endswith('_THRESHOLDS'): + value = f'"{value}"' + new_lines.append(f'{key} = {value}\n') + else: + new_lines.append(line) + + # Write back to file + with open(CONFIG_FILE, 'w') as f: + f.writelines(new_lines) + +def read_logs(hours=24): + """Read the last N hours of log data""" + data = { + 'timestamps': [], + 'temperature': [], + 'humidity': [], + 'uva': [], + 'uvb': [], + 'uvc': [], + 'light': [], + 'heat': [] + } + + try: + with open(LOG_FILE, 'r') as f: + reader = csv.reader(f) + for row in reader: + try: + print(row[0],row[1]) + timestamp = datetime.strptime(row[0] + "." + row[1], '%Y-%m-%d %H:%M:%S.%f') + data['timestamps'].append(timestamp.strftime('%Y-%m-%d %H:%M')) + data['temperature'].append(float(row[2])) + data['humidity'].append(float(row[3])) + data['uva'].append(float(row[4])) + data['uvb'].append(float(row[5])) + data['uvc'].append(float(row[6])) + data['light'].append(int(row[7])) + data['heat'].append(int(row[8])) + except (ValueError, IndexError) as e: + print(e) + continue + except FileNotFoundError: + print(f"{LOG_FILE} not found") + pass + + return data + +@app.route('/') +def index(): + """Render the main page""" + config = read_config() + return render_template('index.html', config=config) + +@app.route('/api/config', methods=['GET']) +def get_config(): + """Get current configuration""" + return jsonify(read_config()) + +@app.route('/api/config', methods=['POST']) +def update_config(): + """Update configuration""" + try: + new_config = request.get_json() + write_config(new_config) + # Restart the gecko-controller service to apply changes + os.system('systemctl restart gecko-controller') + return jsonify({'status': 'success'}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 400 + +@app.route('/api/logs') +def get_logs(): + """Get log data""" + hours = request.args.get('hours', default=24, type=int) + return jsonify(read_logs(hours)) + +def main(): + app.run(host='0.0.0.0', port=8080) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/gecko_controller/web/templates/index.html b/gecko_controller/web/templates/index.html new file mode 100644 index 0000000..602b8fa --- /dev/null +++ b/gecko_controller/web/templates/index.html @@ -0,0 +1,277 @@ + + + + + + Gecko Controller + + + + +
+

Gecko Controller

+ +
+
+

Temperature & Humidity

+
+ +
+
+ +
+

UV Levels

+
+ +
+
+
+ +
+

Settings

+
+
+
+

Temperature

+ + + + + + + + +
+ +
+

Schedule

+ + + + + +
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/setup.py b/setup.py index aa5f19b..f822df6 100644 --- a/setup.py +++ b/setup.py @@ -4,15 +4,23 @@ name="gecko_controller", version="0.4.5", packages=find_packages(), + package_data={ + 'gecko_controller': [ + 'fonts/*', + 'web/templates/*' + ] + }, install_requires=[ - "RPi.GPIO", - "smbus2", - "Pillow", # Added for display functionality + 'smbus2', + 'pillow', + 'RPi.GPIO', + 'flask' ], entry_points={ 'console_scripts': [ 'gecko-controller=gecko_controller.controller:main', - ], + 'gecko-web=gecko_controller.web.app:main' + ] }, python_requires='>=3.9', author="Ian Ross Williams", @@ -20,5 +28,5 @@ description="Raspberry Pi-based temperature, light and UV controller for gecko enclosure", long_description="Automated temperature and light controller for gecko enclosure with OLED display support. " "Features include temperature and humidity monitoring, light cycle control, " - "heat management, and OLED status display.", + "heat management, and OLED status display." ) \ No newline at end of file