Create two clean Arduino sketches for my FabAcademy final project. I need one sketch for the BLE sender unit and one sketch for the BLE receiver / lamp unit. Use Arduino framework for ESP32 boards. General goal: The sender reads three VL53L0X ToF sensors and maps their distances to three color values from 0 to 200. These values are sent once per second as a simple BLE string to the receiver. The receiver controls a WS2812B LED strip with FastLED and updates the lamp color every 500 ms. Use these libraries: * Wire.h * VL53L0X.h * BLEDevice.h / ESP32 BLE library * FastLED.h on the receiver Do not use WiFi, ESP-NOW, multiple modes or complex logic. This is only the final basic live control version. Sender hardware pins: ```cpp constexpr uint8_t XSHUT1_PIN = 1; constexpr uint8_t XSHUT2_PIN = 2; constexpr uint8_t XSHUT3_PIN = 21; constexpr uint8_t SDA_PIN = 22; constexpr uint8_t SCL_PIN = 23; constexpr uint8_t BUTTON_PIN = 17; constexpr uint8_t BATTERY_PIN = 0; ``` Receiver hardware pins: ```cpp #define LED_PIN 10 #define NUM_LEDS 236 #define LED_TYPE WS2812B #define COLOR_ORDER GRB #define HIGH_PIN 7 ``` Receiver: * Set `HIGH_PIN` permanently HIGH in setup. * Use FastLED with 236 WS2812B LEDs on GPIO10. * All LEDs should show the same RGB color. * The maximum channel value is 200. * Never exceed 200 for R, G or B. * Update the LEDs every 500 ms. * If a received sensor/channel is out of range or invalid, use 0 for that color channel, not 200. BLE: Use BLE communication again. Use the same style as a BLE client sender and BLE server receiver. Use these UUIDs: ```cpp static BLEUUID SERVICE_UUID("7e08f6a0-3f3f-4b55-a0a2-8c30f6f19a10"); static BLEUUID CHARACTERISTIC_UUID("4b5f3e26-87d1-48de-9f14-6e0f9e4c7811"); ``` The receiver should advertise the service UUID. The sender should scan for the receiver, connect, find the characteristic and write the current values to it. If the connection is lost, the sender should retry automatically. Keep BLE logic robust but simple. Sensor setup: Use three VL53L0X sensors on one I2C bus. Initialize them with XSHUT pins and assign individual addresses: ```cpp constexpr uint8_t SENSOR1_ADDR = 0x30; constexpr uint8_t SENSOR2_ADDR = 0x31; constexpr uint8_t SENSOR3_ADDR = 0x32; ``` Important sensor order correction: The physical sensor objects are not in the logical order. Correct logical order: 1. Physical Sensor 1 stays Logical Sensor 1. 2. Physical Sensor 3 is actually Logical Sensor 2, the middle sensor. 3. Physical Sensor 2 is actually Logical Sensor 3, the outer sensor. So the final transmitted order must be: ```text logical1 = physical sensor1 logical2 = physical sensor3 logical3 = physical sensor2 ``` Assume the color mapping: ```text Logical Sensor 1 -> Red Logical Sensor 2 -> Green Logical Sensor 3 -> Blue ``` Distance calibration: Each sensor has its own zero distance because the mechanical integration creates different covered-distance values. Use these individual zero points: ```cpp constexpr int ZERO_SENSOR1_MM = 41; // physical sensor 1 covered range: 35-41 mm constexpr int ZERO_SENSOR3_MM = 82; // physical sensor 3, logical middle sensor, covered range: 75-82 mm constexpr int ZERO_SENSOR2_MM = 55; // physical sensor 2, logical outer sensor, covered range: 45-55 mm ``` Mapping rule: * At the individual zero point, the color value must be 0. * At 500 mm, the color value must be 200. * Between zero point and 500 mm, map linearly. * Below the zero point, clamp to 0. * Above 500 mm, do not map to 200. Treat it as out of range. * Invalid readings, timeouts and readings above 500 mm must be marked as out of range. * Out-of-range values should be sent in a way that the receiver can recognize, for example as `-1`. Suggested BLE string format: Use a simple readable format: ```text R=120;G=44;B=-1;BAT=3.87 ``` Receiver parsing: * Parse `R`, `G`, and `B`. * Clamp valid values to 0...200. * If a value is `-1`, treat it as out of range and use 0 for that channel. * Ignore `BAT` on the receiver for LED control, but it is okay to print it in Serial for debugging. Sender serial output: Every second, print: * raw physical sensor values * corrected logical sensor values * mapped R/G/B values * out-of-range status * battery voltage * button state Battery measurement: Read battery voltage on GPIO0 / A0. Use `analogReadMilliVolts(BATTERY_PIN)`. Average several samples, for example 16. Use a voltage divider factor of 2.0: ```cpp constexpr float BATTERY_DIVIDER_FACTOR = 2.0; ``` Button: The button is connected to GPIO17. Use `INPUT_PULLUP`. The raw electrical state is: * released = HIGH * pressed = LOW Print both the raw state and a logical pressed state: * pressed = HIGH in the Serial output * released = LOW in the Serial output The button does not need to change modes because there is only one mode. Code quality: * Keep both sketches clean and readable. * Use constants at the top. * Add clear comments. * Avoid unnecessary abstraction. * Avoid delay-heavy logic except small startup delays and ADC averaging. * Use `millis()` timing for the 1 Hz sender update and 500 ms receiver LED update. * Include good Serial debug output. * Make the code suitable for quick testing during final project debugging. Additional receiver relay logic: The receiver pin `HIGH_PIN` is the relay control pin. Do not keep `HIGH_PIN` permanently HIGH anymore. Instead, control it depending on the mapped LED color values. Add clear relay state constants because the relay module may be low-level triggered: ```cpp constexpr uint8_t RELAY_ON_STATE = LOW; constexpr uint8_t RELAY_OFF_STATE = HIGH; ``` Logic: * If all final LED color values are 0, switch the relay OFF. * If at least one final LED color value is greater than 0, switch the relay ON. * Out-of-range sensor values are already converted to 0 before this check. * The relay state should be updated together with the LED update every 500 ms. Example logic: ```cpp bool allChannelsOff = (currentR == 0 && currentG == 0 && currentB == 0); if (allChannelsOff) { digitalWrite(HIGH_PIN, RELAY_OFF_STATE); } else { digitalWrite(HIGH_PIN, RELAY_ON_STATE); } ``` Also print the relay state in the Serial Monitor for debugging: ```cpp Serial.print("Relay: "); Serial.println(allChannelsOff ? "OFF" : "ON"); ``` Afterwards I added the following prompt: All top. But please rewrite the lamp code, the relais has to be inverted. (safe as v3)