diff --git a/lib/hardware/library.json b/lib/hardware/library.json new file mode 100644 index 0000000..8789ba7 --- /dev/null +++ b/lib/hardware/library.json @@ -0,0 +1,6 @@ +{ + "name": "hardware", + "dependencies": { + "nanopb": "*" + } +} diff --git a/lib/ota/library.json b/lib/ota/library.json new file mode 100644 index 0000000..bd07111 --- /dev/null +++ b/lib/ota/library.json @@ -0,0 +1,6 @@ +{ + "name": "ota", + "dependencies": { + "hardware": "*" + } +} diff --git a/lib/ota/ota_update.cpp b/lib/ota/ota_update.cpp new file mode 100644 index 0000000..1637fc5 --- /dev/null +++ b/lib/ota/ota_update.cpp @@ -0,0 +1,85 @@ +#include "ota_update.hpp" + +OtaUpdate::OtaUpdate() + : _server(80), _httpUpdater(), _configured(false), _startTime(0) { +} + +bool OtaUpdate::configure(const hardware_SensorOTAEnable& config) { + _config = config; + _configured = true; + _startTime = millis(); + + // Disconnect if already connected + WiFi.disconnect(); + delay(100); + + if (_config.as_station_mode) { + // STA mode + WiFi.mode(WIFI_STA); + WiFi.begin(_config.ssid, _config.password); + + Serial.print("Connecting to WiFi STA: "); + Serial.println(_config.ssid); + + unsigned long startAttempt = millis(); + while (WiFi.status() != WL_CONNECTED && millis() - startAttempt < 10000) { + delay(500); + Serial.print("."); + } + + if (WiFi.status() != WL_CONNECTED) { + Serial.println("Failed to connect to WiFi"); + _configured = false; + return false; + } + + if (_config.use_static_ip) { + IPAddress ip, gateway, subnet; + ip.fromString(_config.static_ip); + gateway.fromString(_config.gateway); + subnet.fromString(_config.netmask); + WiFi.config(ip, gateway, subnet); + } + + Serial.println(""); + Serial.print("Connected to "); + Serial.println(_config.ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } else { + // AP mode + WiFi.mode(WIFI_AP); + WiFi.softAP(_config.ssid, _config.password); + + Serial.print("Started AP: "); + Serial.println(_config.ssid); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + } + + // Setup HTTP Update Server + _httpUpdater.setup(&_server); + _server.begin(); + Serial.println("HTTP Update Server started"); + + return true; +} + +void OtaUpdate::update() { + if (!_configured) return; + + _server.handleClient(); + + // Check timeout + if (_config.timeout_seconds > 0 && millis() - _startTime > _config.timeout_seconds * 1000) { + Serial.println("OTA timeout, disabling WiFi"); + disable(); + } +} + +void OtaUpdate::disable() { + _server.stop(); + WiFi.disconnect(); + _configured = false; + Serial.println("OTA disabled"); +} \ No newline at end of file diff --git a/lib/ota/ota_update.hpp b/lib/ota/ota_update.hpp new file mode 100644 index 0000000..eb7e6ad --- /dev/null +++ b/lib/ota/ota_update.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "hardware.pb.h" +#include +#include +#include + +class OtaUpdate { +public: + OtaUpdate(); + bool configure(const hardware_SensorOTAEnable& config); + void update(); + void disable(); + +private: + hardware_SensorOTAEnable _config; + ESP8266WebServer _server; + ESP8266HTTPUpdateServer _httpUpdater; + bool _configured; + unsigned long _startTime; +}; diff --git a/platformio.ini b/platformio.ini index a675c18..7262e46 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,6 +20,7 @@ lib_deps = ;adafruit/Adafruit NeoPixel@^1.15.1 fastled/FastLED@^3.10.3 nanopb/Nanopb@^0.4.91 + ; jandrassy/ArduinoOTA @ ^1.1.0 custom_nanopb_protos = + custom_nanopb_options = @@ -27,3 +28,8 @@ custom_nanopb_protos = [env:esp8285] platform = espressif8266 board = esp12e +[env:esp8285-ota] +platform = espressif8266 +board = esp12e +upload_protocol = espota +upload_port = 192.168.20.41 \ No newline at end of file diff --git a/proto/hardware.options b/proto/hardware.options index 9e8624e..ce35ac4 100644 --- a/proto/hardware.options +++ b/proto/hardware.options @@ -1,4 +1,12 @@ # Nanopb options for hardware.proto # LED configuration -hardware.FadeParams.colors max_count:5 \ No newline at end of file +hardware.FadeParams.colors max_count:5 + +hardware.SensorOTAEnable.ssid max_length:32 +hardware.SensorOTAEnable.password max_length:64 +hardware.SensorOTAEnable.static_ip max_length:16 +hardware.SensorOTAEnable.netmask max_length:16 +hardware.SensorOTAEnable.gateway max_length:16 +hardware.SensorOTAEnableResponse.ip_address max_length:16 +hardware.SensorOTAEnableResponse.error_message max_length:64 \ No newline at end of file diff --git a/proto/hardware.proto b/proto/hardware.proto index 1f74a55..8abeaef 100644 --- a/proto/hardware.proto +++ b/proto/hardware.proto @@ -23,6 +23,8 @@ message HardwareConfig { bool enable_serial_sensor = 9; // repeated char sensor_api_key = 10; // bool enable_ws_sensor = 11; + LedConfig on_override_open_led = 12; + LedConfig on_interception_led = 13; } // LED configuration @@ -61,19 +63,37 @@ message RfidReading { } message SensorToControlMessage { - uint32 sensor_id = 1; - oneof payload { - RfidReading rfid_reading = 2; - // Add other sensor message types as needed - } + uint32 sensor_id = 1; + oneof payload { + RfidReading rfid_reading = 2; + SensorOTAEnableResponse ota_response = 3; + // Add other sensor message types as needed + } } +message SensorOTAEnable { + string ssid = 1; + string password = 2; + uint32 timeout_seconds = 3; + bool as_station_mode = 4; + bool use_static_ip = 5; + string static_ip = 6; + string netmask = 7; + string gateway = 8; +} + +message SensorOTAEnableResponse { + bool success = 1; + string ip_address = 2; + string error_message = 3; +} message ControlToSensorMessage { uint32 control_id = 1; oneof payload { LedConfig led_config = 2; + SensorOTAEnable ota_enable = 3; // Add other control message types as needed } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3b2414d..9428d5e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,8 +2,11 @@ #include #include #include +#include #include "hardware.pb.h" +OtaUpdate ota; + // Demo for HardwareLed HardwareLed<2> led; // Assuming NeoPixel on pin 2 (D2 on ESP8266) @@ -27,62 +30,51 @@ void onRfidTag(const hardware_SensorToControlMessage& msg) { void onSerialMessage(const IncomingMessage& msg) { if (msg.which_payload == hardware_ControlToSensorMessage_led_config_tag) { led.set(msg.payload.led_config); + } else if (msg.which_payload == hardware_ControlToSensorMessage_ota_enable_tag) { + hardware_SensorOTAEnableResponse response = {0}; + response.success = ota.configure(msg.payload.ota_enable); + if (response.success) { + IPAddress ip = WiFi.localIP(); + if (!msg.payload.ota_enable.as_station_mode) { + ip = WiFi.softAPIP(); + } + strcpy(response.ip_address, ip.toString().c_str()); + } else { + strcpy(response.error_message, "Failed to configure OTA"); + } + + hardware_SensorToControlMessage responseMsg = {0}; + responseMsg.sensor_id = msg.control_id; // or some id + responseMsg.which_payload = hardware_SensorToControlMessage_ota_response_tag; + responseMsg.payload.ota_response = response; + + serial.sendMessage(responseMsg); } } void setup() { Serial.begin(9600); + led.begin(); rfid.begin(); rfid.setCallback(onRfidTag); serial.begin(Serial); serial.setCallback(onSerialMessage); - // // Static config - // configs[0] = {0}; - // configs[0].brightness = 128; - // configs[0].duration_ms = 0; - // configs[0].which_animation_params = 3; - // configs[0].animation_params.static_params.color = 0x00FF00; // Green + // Static config + configs[0] = {0}; + configs[0].brightness = 128; + configs[0].duration_ms = 0; + configs[0].which_animation_params = 3; + configs[0].animation_params.static_params.color = 0x00FF00; // Green - // // Pulse config - // configs[1] = {0}; - // configs[1].brightness = 128; - // configs[1].duration_ms = 0; - // configs[1].which_animation_params = 4; - // configs[1].animation_params.pulse_params.color = 0xFF0000; // Red - // configs[1].animation_params.pulse_params.speed_ms = 500; - // // Fade config - // configs[2] = {0}; - // configs[2].brightness = 128; - // configs[2].duration_ms = 0; - // configs[2].which_animation_params = 5; - // configs[2].animation_params.fade_params.colors_count = 3; - // configs[2].animation_params.fade_params.colors[0] = 0xFF0000; // Red - // configs[2].animation_params.fade_params.colors[1] = 0x00FF00; // Green - // configs[2].animation_params.fade_params.colors[2] = 0x0000FF; // Blue - // configs[2].animation_params.fade_params.speed_ms = 1000; - - // // Flicker config - // configs[3] = {0}; - // configs[3].brightness = 128; - // configs[3].duration_ms = 0; - // configs[3].which_animation_params = 6; - // configs[3].animation_params.flicker_params.color = 0xFFFFFF; // White - // configs[3].animation_params.flicker_params.intensity = 50; - - // led.set(configs[0]); + led.set(configs[0]); } void loop() { led.update(); rfid.update(); serial.update(); - - // if (millis() - lastChange >= 10000) { - // lastChange = millis(); - // currentConfig = (currentConfig + 1) % 4; - // led.set(configs[currentConfig]); - // } + ota.update(); } \ No newline at end of file