├── .vscode └── settings.json ├── 3D_file_esp32_coop.Stl ├── README.md └── exemple ├── BLE.js ├── blinkBLE └── blinkBLE.ino ├── blinkBLEv2 └── blinkBLEv2.ino ├── esp32time └── esp32time.ino ├── index.html ├── index2.html ├── index3.html ├── index4.html ├── index5.html └── setime └── setime └── setime.ino /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /3D_file_esp32_coop.Stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ESP32-COOP/ESP32-COOP-DOC/b0bf2057fa12e004c3d627c7f62ad95596e55f8a/3D_file_esp32_coop.Stl -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | logo JS-BLE-DOC 3 | 4 | # [ :book: ESP32 Coop Door Documentation ](https://coop-door.vercel.app/) 5 | 6 | The goal is to document the setup & configuration of the [esp32-coop](https://github.com/ESP32-COOP) project as well as the protocol in which the two devices communicate over BLE 7 |
8 | 9 | 10 | # :memo: Summary: 11 | 12 | - [:page_facing_up: **Project Overview**](page_facing_up-project-overview): quick presentation of the mother project (goal, link device, protocol used, problematic) 13 | - [:iphone: **The App**](#iphone-app-installation): how to get the it 14 | - [:toolbox: **Build instruction**](#toolbox-build-instruction) 15 | - :clipboard: Requirement 16 | - :flashlight: Wiring 17 | - :rocket: First Boot 18 | - :house: 3D file 19 | - :signal_strength: **Communication protocol** 20 | - :electric_plug: Run-down on how BLE works 21 | - :bar_chart: The type of data required by the project (in progress) 22 | - :computer: Code snippet for each characteristic (in progress) 23 | 24 | 25 | # :page_facing_up: Project Overview 26 | 27 | 28 | 29 | plan 30 | 31 | 32 | The [COOP-DOOR](https://github.com/ESP32-COOP) project aims to create an intelligent and user-friendly automatic coop door system. It empowers users to customize the door's behavior based on specific conditions, such as time and light levels. To facilitate device management and monitoring, the project offers a mobile app. 33 | 34 | The app enables users to track device and sensor health, as well as configure various operating conditions. For a demonstration of the project, please refer to the demo [here](https://github.com/ESP32-COOP/ESP32-COOP-DOOR-WEB). The core of the smart coop door relies on the ESP-32 platform, and the code repository can be found [here](https://github.com/ESP32-COOP/ESP32-COOP-DOOR-CORE). 35 | 36 | This documentation page aims to guide users through the setup process, hardware requirements, and detailed workings of the system. 37 | 38 |
39 | 40 | 41 | # :iphone: App Installation 42 | 43 | 44 | app icon 45 |
46 | The coop door application is a Progressive Web App, meaning it functions as a website and can be installed on mobile devices for offline usage. 47 |
48 |
49 | 50 | To install the app, follow these steps: 51 | 52 | 1. Visit [coop-door.vercel.app](https://coop-door.vercel.app) using your mobile device's web browser. 53 | 2. A small popup will prompt you to install the app. Tap "Install" to proceed. 54 | 3. Alternatively, if the popup doesn't appear, you can manually add the app to your home screen by: 55 | - Tapping the three dots in Chrome. 56 | - Scrolling down and selecting "Add shortcut to home screen" or "Install app." 57 | 4. The app will be installed on your device and accessible from the home screen. 58 | 59 | Now, you can conveniently use the mobile app to monitor and control your coop door system, even without an internet connection. 60 | 61 | 62 | # :toolbox: Build instruction 63 | 64 | Look out for instruction variations depending on the version of the project you're building. 65 | 66 | First of all, you will need to flash the firmware on the ESP32. Please refer to the instructions [here](https://github.com/ESP32-COOP/ESP32-COOP-DOOR-CORE). I do recommend unplugging the motor before flashing the firmware to avoid any connection problems caused by the encoder or any accidental movement of the powered motor. 67 | 68 | ## :clipboard: Requirement 69 | 70 | 71 | This projet use :
72 | - a ESP32 [WEMOS lolin32 lite](https://fr.aliexpress.com/item/4000038780903.html?spm=a2g0o.productlist.main.1.365b7074KBRyQT&algo_pvid=fa4a7510-076f-4fb9-8ed4-3253a3a69928&algo_exp_id=fa4a7510-076f-4fb9-8ed4-3253a3a69928-0&pdp_npi=4%40dis%21EUR%212.40%212.4%21%21%212.56%21%21%402132a21116927149487777888ec3b7%2112000030098281375%21sea%21FR%21821278985%21&curPageLogUid=oNK3v7tChtb8) ( can be any esp32 with BLE),
73 | - a H-Bridge [l298n](https://fr.aliexpress.com/item/1005004510885871.html?spm=a2g0o.productlist.main.1.4ab84eaai4P1f2&algo_pvid=83586f20-9cd5-4dc6-a3a3-c75def78a4cb&algo_exp_id=83586f20-9cd5-4dc6-a3a3-c75def78a4cb-0&pdp_npi=4%40dis%21EUR%211.74%211.53%21%21%211.85%21%21%402132a21116927149924648112ec3b7%2112000029421559001%21sea%21FR%21821278985%21&curPageLogUid=vMEusi5qQJYG),
74 | - a [motor with a encoder](https://fr.aliexpress.com/item/4001314473291.html?spm=a2g0o.productlist.main.1.52dd699a8YKYiK&algo_pvid=2a4b28bb-bc90-458b-ae85-f85eb2cfdece&algo_exp_id=2a4b28bb-bc90-458b-ae85-f85eb2cfdece-0&pdp_npi=4%40dis%21EUR%215.76%215.76%21%21%216.14%21%21%402132a21116927150494998265ec3b7%2110000015695661379%21sea%21FR%21821278985%21&curPageLogUid=HH3ljdlfyhi0),
75 | - and a [photoresistor](Vhttps://fr.aliexpress.com/item/32760631393.html?spm=a2g0o.productlist.main.1.5dd44f76NrlFVE&algo_pvid=25a08ae4-57ee-4d4c-91c6-76967f27dc4b&algo_exp_id=25a08ae4-57ee-4d4c-91c6-76967f27dc4b-0&pdp_npi=4%40dis%21EUR%210.72%210.6%21%21%210.77%21%21%402132f35616927151872427277e2c69%2110000001115154392%21sea%21FR%21821278985%21&curPageLogUid=ZBl0dvCbwSIm) 76 | 77 | Additionally, you'll need some basic items such as wires, soldering equipment (or soldering iron), and a 3D printer or woodworking tools, depending on your preferences. 78 | 79 | Please note that you can easily swap out any component of this project for a similar one. It will most likely work out fine, but it may require some extra work. I would recommend it only to experienced thinkers. 80 | 81 | ## :electric_plug: Wiring 82 | As illustrated below, follow these connections: 83 | 84 | ESP32: 85 | - Connect encoder signal to pin 2 (yellow) and pin 15 (green). 86 | - Attach a resistor to pin 34 for analog value. 87 | - Control the H-bridge with pins 27 (ENA), 26 (IN1), and 15 (IN2). 88 | 89 | Remember to establish a ground connection between the H-bridge and the ESP32. 90 | 91 | wiring diagram 92 | 93 | ## :rocket: Initial Setup 94 | 95 | **Before Coop Installation:** 96 | 97 | It's a good idea to run comprehensive tests before installing the device in the coop. Debugging is much easier and less frustrating when you're comfortably situated in a well-ventilated room. 98 | 99 | **Initial ESP32 Boot:** 100 | 101 | When the ESP32 boots up initially, it assumes the door is closed. If that's not the case, unplug either the motor or the ESP and manually close the door. 102 | 103 | **Proper Device Boot:** 104 | 105 | Now you can properly start up your device. Inside the app, go to settings and then to the door section. Set the number of rotations you want the motor to perform in order to open the door. Click the test button, and the motor will complete a full cycle (going up and then back down). Begin with a small rotation number, and gradually adjust it until you reach your desired door height. 106 | 107 | **Optimal Rotation Value:** 108 | 109 | Once you've figured out the best number of motor rotations, jot down this value along with the light sensor reading. To sync the ESP32's time, head to the app's home page and click on the time badge. A panel will appear, showing the time difference between your phone and the ESP32, along with a sync button. 110 | 111 | **Setting Conditions:** 112 | 113 | With that sorted, configure open and closing conditions in the door settings. Base these conditions solely on time, and set the door to stay open for the rest of the day. 114 | 115 | **Chicken Entry Time:** 116 | 117 | Return to the coop at the designated chicken entry time to check the light sensor value. If needed, adjust the closing condition within the app's settings. 118 | 119 | **Autonomous Operation:** 120 | 121 | To enable autonomous operation, revisit the settings and door page. Click on 'auto' and then 'apply'. 122 | 123 | ## :carpentry_saw: Casing Details 124 | 125 | You can find the 3D model at this [link](https://github.com/ESP32-COOP/JS-BLE-DOC/blob/main/3D_file_esp32_coop.stl), and the technical drawing is available //todo. 126 | 127 | # :signal_strength: Wireless comunication 128 | ## :loudspeaker: BLE Protocol 129 | 130 | BLE illustration 131 |
132 | To better understand the following, you must understand the basics of the Bluetooth Low Energy (BLE) protocol.
133 | The key part to understand is that it uses a fixed-size array of bytes to send data to an endpoint. 134 |
135 |
136 | 137 | 138 | 139 | Each endpoint can have three properties: writable, readable, and notifyable. 140 | 141 | - Writable: It allows the external user to write/edit the endpoint (officially called characteristic in BLE). 142 | - Readable: It allows reading the characteristic's value. 143 | - Notifyable: It allows getting notified when that value is updated. 144 | 145 | A byte is made out of 8 bits, and its value can go from 0 to 255. 146 | 147 | To send the desired value in bytes, you must think it through: 148 | 149 | - You will need to figure out the array size you will need and the function to convert it back and forth in C and in JS. 150 | 151 | Currently, there are five communication subjects: 152 | 1. The light sensor (made out of 4 bytes). 153 | 2. The time (made out of 9 bytes, 8 to represent UNIX time and 1 to represent the UTC offset). 154 | 3. The closing condition 155 | 4. The opening condition 156 | 5. Door settings 157 | 158 | ## :bulb: Data size 159 | 160 | With BLE the goal is to send the smallest array posible 161 | 162 | for each communication subjects i will justify each bytes and explain it's encoding 163 | 164 | 1. **The light sensor** produces 4 bytes of data. Our objective is to transmit the current value, along with the minimum and maximum values recorded by the sensor. To achieve this, we need an additional variable called a "divider." The maximum sensor value is fixed at 1024, while the highest value representable by a byte is 255. 165 | 166 | Calculating the divider is straightforward: we divide the maximum sensor value of 1024 by 255. This gives us the scaling factor needed for our encoding. 167 | 168 | With the divider in hand, we can create an encoded transmission as follows: 169 | - Current Value: current_value / divider 170 | - Minimum Value: min_value / divider 171 | - Maximum Value: max_value / divider 172 | - Unused Placeholder: (for the divider value) 173 | 174 | Reverting back to the original values is easy: simply multiply by the divider. This process maintains the integrity of the data throughout the encoding and decoding stages. 175 | 2. **The time** use 9 bytes The initial 8 bytes encode the UNIX time, while the ninth byte stores the user's country time offset. 176 | 177 | **Encoding UNIX Time**: 178 | To encode the UNIX time: 179 | - Begin by taking the lowest 8 bits of the time value using a bitwise AND operation with 0xff. 180 | - Place this extracted value in the current byte of the array. 181 | - Divide the time value by 256 to discard the lowest 8 bits for the next step. 182 | 183 | **Decoding UNIX Time**: 184 | To decode the UNIX time: 185 | - Set up a variable to hold the decoded time value. 186 | - Iterate eight times (for each byte), starting from the most significant byte down to the least: 187 | - Multiply the current result by 256 (shift left by 8 bits) to make room for the next byte. 188 | - Add the value of the current byte to the result. 189 | 190 | **Encoding Time Offset**: 191 | Encoding the time offset is simple. You subtract the time offset from 12 and then add back 12 during decoding. This process is necessary because the time offset ranges from -12 to 12. 192 | 193 | 3. **Door Condition** use 4 bytes, used by both open condtion and closing condtion. 194 | We ne the following value: the door mode (checking for light or time), the threshold and finaly the time 195 | The array is form like this [door_mode, light_treshold / 4, time hour, time minutes] 196 | The door mode is represented by a single digit, reflecting various modes: 197 | - 0 : do nothing 198 | - 1 : change on light condition 199 | - 2 : change on time condition 200 | - 3 : change on light and time condition 201 | - 4 : change on light or time condition 202 | By adopting this array format and the corresponding door modes, we efficiently handle door conditions during both opening and closing situations. 203 | 4. **Door settings** use 2 bytes, with the following needed value the door mode and the number of turn. 204 | 205 | The door mode can take on various values: 206 | - 0: Door closed 207 | - 1: Door open 208 | - 2: Test door (opens and closes immediately) 209 | - 10: Automatic mode with the door closed 210 | - 11: Automatic mode with the door open 211 | 212 | **Number of Turns Encoding**: 213 | To encode the number of turns, we simply multiply the value by 10. 214 | 215 | Here's the array structure for encoding: [door_mode, number_of_turns * 10]. 216 | 217 | ## :gear: Code Snippette 218 | Certainly, here's your code snippet presented in a more readable manner: 219 | 220 | ## Encoding and Decoding Long Numbers to Bytes 221 | 222 | Here, we present functions for encoding and decoding long numbers into bytes. These functions are particularly relevant for working with the UNIX time standard. We provide the code snippets for both C and JavaScript: 223 | 224 | ### C Implementation 225 | 226 | ```c 227 | byte* getBytesFromLong(long x) { 228 | byte* bytes = new byte[8]; 229 | for (int i = 0; i < 8; i++) { 230 | bytes[i] = x & 0xff; 231 | x = (x - bytes[i]) / 256; 232 | } 233 | return bytes; 234 | } 235 | 236 | long getLongFromBytes(const byte* bytes) { 237 | long result = 0; 238 | for (int i = 7; i >= 0; i--) { 239 | result = (result * 256) + bytes[i]; 240 | } 241 | return result; 242 | } 243 | ``` 244 | 245 | ### JavaScript Implementation 246 | 247 | ```javascript 248 | export function getLongFromBytesBuffer(bytes) { 249 | let result = 0; 250 | for (let i = 7; i >= 0; i--) { 251 | result = result * 256 + bytes.getUint8(i); 252 | } 253 | return result; 254 | } 255 | 256 | export function getArrayFromBuffer(bytes, len) { 257 | let result = []; 258 | for (let i = 0; i < len; i++) { 259 | result.push(bytes.getUint8(i)); 260 | } 261 | return result; 262 | } 263 | ``` 264 | 265 | These functions offer efficient ways to convert long numbers to byte arrays and vice versa, which is particularly useful for working with the UNIX time standard. The C and JavaScript implementations cater to different programming environments, ensuring flexibility in usage. 266 | 267 | 268 | ## Tutorial 269 | Here is a video that explain how the BLE work 270 | //todo 271 | ![Communication between JS and an ESP32](https://github.com/ESP32-COOP/JS-BLE-LIB/assets/37497007/fc5af1d0-81f3-4928-ad49-e429e57f3b67) 272 | -------------------------------------------------------------------------------- /exemple/BLE.js: -------------------------------------------------------------------------------- 1 | let id; 2 | let bluetoothDeviceDetected; 3 | let service; 4 | let GATT_date; 5 | 6 | 7 | let dateService = '1ce76320-2d32-41af-b4c4-46836ea7a62a'.toLowerCase(); 8 | let dateChar = 'ad804469-19ec-406a-b949-31ae17e43813'.toLowerCase(); 9 | 10 | const deviceName = 'COOP-DOOR'; 11 | 12 | 13 | function iSWebBLEAvailable() { 14 | if (!navigator.bluetooth){ 15 | console.log('not available'); 16 | return false; 17 | } 18 | return true; 19 | 20 | } 21 | function getDeviceInfo() { 22 | let options = { 23 | //acceptAllDevices: true, 24 | optionalServices : [dateService, dateChar ], 25 | filters : [ 26 | {namePrefix: deviceName} 27 | ] 28 | } 29 | 30 | console.log("Requestion BLE device info...") 31 | return navigator.bluetooth.requestDevice(options).then(device => { 32 | bluetoothDeviceDetected = device; 33 | console.log('name '+device.name); 34 | }).catch(error => { 35 | console.log('Request device error: '+error); 36 | }) 37 | } 38 | 39 | async function connectGATT(){ 40 | 41 | deviceConnected = await bluetoothDeviceDetected.gatt.connected; 42 | server = await bluetoothDeviceDetected.gatt.connect() 43 | 44 | service2 = await server.getPrimaryService(dateService); 45 | GATT_date = await service2.getCharacteristic(dateChar); 46 | 47 | } 48 | async function readChar(char) { 49 | const dump = await char.readValue() 50 | return dump 51 | } 52 | 53 | async function readDate() { 54 | const dump = await readChar(GATT_date) 55 | console.log(dump) 56 | return getLongFromBytesBuffer(dump) 57 | } 58 | 59 | function writeDate(){ 60 | 61 | let now = Math.round(Date.now() / 1000); //Date.now(); 62 | let bytes = getBytesFromLong(now); 63 | console.log(now,bytes,getLongFromBytes(bytes)) 64 | let buffer = new Uint8Array(bytes).buffer; 65 | GATT_date.writeValue(buffer); 66 | } 67 | 68 | function getBytesFromLong(x) { 69 | let bytes = new Array(8); 70 | for (let i = 0; i < 8; i++) { 71 | bytes[i] = x & 0xff; 72 | x = (x - bytes[i]) / 256; 73 | } 74 | return bytes; 75 | } 76 | 77 | 78 | 79 | 80 | 81 | function getLongFromBytes(bytes) { 82 | let result = 0; 83 | for (let i = 7; i >= 0; i--) { 84 | result = (result * 256) + bytes[i]; 85 | } 86 | return result; 87 | } 88 | function getLongFromBytesBuffer(bytes) { 89 | let result = 0; 90 | for (let i = 7; i >= 0; i--) { 91 | result = (result * 256) + bytes.getUint8(i); 92 | } 93 | return result; 94 | } 95 | 96 | -------------------------------------------------------------------------------- /exemple/blinkBLE/blinkBLE.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Bluetooth® Low Energy LED Service 4 | 5 | // Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central 6 | BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); 7 | BLEByteCharacteristic switchCharacteristic2("77a57c66-3bc9-463a-bc52-1ee5763b9c0f", BLERead | BLENotify); 8 | 9 | const int ledPin = LED_BUILTIN; // pin to use for the LED 10 | uint8_t ble_value = 0x0; 11 | 12 | void setup() { 13 | Serial.begin(9600); 14 | while (!Serial); 15 | 16 | // set LED pin to output mode 17 | pinMode(ledPin, OUTPUT); 18 | 19 | // begin initialization 20 | if (!BLE.begin()) { 21 | Serial.println("starting Bluetooth® Low Energy module failed!"); 22 | 23 | while (1); 24 | } 25 | 26 | // set advertised local name and service UUID: 27 | BLE.setLocalName("COOP-DOOR"); 28 | BLE.setAdvertisedService(ledService); 29 | 30 | // add the characteristic to the service 31 | ledService.addCharacteristic(switchCharacteristic); 32 | ledService.addCharacteristic(switchCharacteristic2); 33 | 34 | // add service 35 | BLE.addService(ledService); 36 | 37 | // set the initial value for the characeristic: 38 | switchCharacteristic.writeValue(0); 39 | switchCharacteristic2.writeValue(0); 40 | 41 | // start advertising 42 | BLE.advertise(); 43 | 44 | Serial.println("BLE LED Peripheral"); 45 | } 46 | 47 | void loop() { 48 | // listen for Bluetooth® Low Energy peripherals to connect: 49 | BLEDevice central = BLE.central(); 50 | 51 | // if a central is connected to peripheral: 52 | if (central) { 53 | Serial.print("Connected to central: "); 54 | // print the central's MAC address: 55 | Serial.println(central.address()); 56 | 57 | // while the central is still connected to peripheral: 58 | while (central.connected()) { 59 | // if the remote device wrote to the characteristic, 60 | // use the value to control the LED: 61 | if (switchCharacteristic.written()) { 62 | Serial.println("update"); 63 | if (switchCharacteristic.value()) { // any value other than 0 64 | Serial.println("LED on"); 65 | digitalWrite(ledPin, HIGH); // will turn the LED on 66 | } else { // a 0 value 67 | Serial.println("LED off"); 68 | digitalWrite(ledPin, LOW); // will turn the LED off 69 | } 70 | } 71 | ble_value = random(0, 11); 72 | switchCharacteristic2.writeValue(ble_value); 73 | } 74 | 75 | // when the central disconnects, print it out: 76 | Serial.print(F("Disconnected from central: ")); 77 | Serial.println(central.address()); 78 | } 79 | 80 | 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /exemple/blinkBLEv2/blinkBLEv2.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Bluetooth® Low Energy LED Service 4 | 5 | // Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central 6 | BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); 7 | BLEByteCharacteristic switchCharacteristic2("77a57c66-3bc9-463a-bc52-1ee5763b9c0f", BLERead | BLENotify); 8 | 9 | BLEService dateService("1ce76320-2d32-41af-b4c4-46836ea7a62a"); // Bluetooth® Low Energy LED Service 10 | BLECharacteristic dateCharacteristic("ad804469-19ec-406a-b949-31ae17e43813", BLERead | BLENotify | BLEWrite,5); 11 | 12 | const int ledPin = LED_BUILTIN; // pin to use for the LED 13 | uint8_t ble_value = 0x0; 14 | 15 | void setup() { 16 | Serial.begin(9600); 17 | while (!Serial); 18 | 19 | // set LED pin to output mode 20 | pinMode(ledPin, OUTPUT); 21 | 22 | // begin initialization 23 | if (!BLE.begin()) { 24 | Serial.println("starting Bluetooth® Low Energy module failed!"); 25 | 26 | while (1); 27 | } 28 | 29 | // set advertised local name and service UUID: 30 | BLE.setLocalName("COOP-DOOR"); 31 | BLE.setAdvertisedService(ledService); 32 | BLE.setAdvertisedService(dateService); 33 | 34 | // add the characteristic to the service 35 | ledService.addCharacteristic(switchCharacteristic); 36 | ledService.addCharacteristic(switchCharacteristic2); 37 | 38 | dateService.addCharacteristic(dateCharacteristic); 39 | 40 | // add service 41 | BLE.addService(ledService); 42 | 43 | BLE.addService(dateService); 44 | 45 | // set the initial value for the characeristic: 46 | switchCharacteristic.writeValue(0); 47 | switchCharacteristic2.writeValue(0); 48 | 49 | dateCharacteristic.writeValue(0); 50 | 51 | // start advertising 52 | BLE.advertise(); 53 | 54 | Serial.println("BLE LED Peripheral"); 55 | } 56 | 57 | void loop() { 58 | // listen for Bluetooth® Low Energy peripherals to connect: 59 | BLEDevice central = BLE.central(); 60 | 61 | // if a central is connected to peripheral: 62 | if (central) { 63 | Serial.print("Connected to central: "); 64 | // print the central's MAC address: 65 | Serial.println(central.address()); 66 | 67 | // while the central is still connected to peripheral: 68 | while (central.connected()) { 69 | // if the remote device wrote to the characteristic, 70 | // use the value to control the LED: 71 | 72 | if (switchCharacteristic.written()) { 73 | Serial.println("update"); 74 | if (switchCharacteristic.value()) { // any value other than 0 75 | Serial.println("LED on"); 76 | digitalWrite(ledPin, HIGH); // will turn the LED on 77 | } else { // a 0 value 78 | Serial.println("LED off"); 79 | digitalWrite(ledPin, LOW); // will turn the LED off 80 | } 81 | } 82 | 83 | if (dateCharacteristic.written()){ 84 | Serial.println("Date update"); 85 | Serial.println(dateCharacteristic.value()[0]); 86 | Serial.println(dateCharacteristic.value()[1]); 87 | Serial.println(dateCharacteristic.value()[2]); 88 | Serial.println(dateCharacteristic.value()[3]); 89 | Serial.println(dateCharacteristic.value()[4]); 90 | } 91 | ble_value = random(0, 11); 92 | switchCharacteristic2.writeValue(ble_value); 93 | } 94 | 95 | // when the central disconnects, print it out: 96 | Serial.print(F("Disconnected from central: ")); 97 | Serial.println(central.address()); 98 | } 99 | 100 | 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /exemple/esp32time/esp32time.ino: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Felix Biego 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | //ESP32Time rtc; 28 | ESP32Time rtc(3600); // offset in seconds GMT+1 29 | 30 | void setup() { 31 | Serial.begin(115200); 32 | rtc.setTime(30, 24, 15, 17, 1, 2021); // 17th Jan 2021 15:24:30 33 | //rtc.setTime(1609459200); // 1st Jan 2021 00:00:00 34 | //rtc.offset = 7200; // change offset value 35 | 36 | /*---------set with NTP---------------*/ 37 | // configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); 38 | // struct tm timeinfo; 39 | // if (getLocalTime(&timeinfo)){ 40 | // rtc.setTimeStruct(timeinfo); 41 | // } 42 | } 43 | 44 | void loop() { 45 | // Serial.println(rtc.getTime()); // (String) 15:24:38 46 | // Serial.println(rtc.getDate()); // (String) Sun, Jan 17 2021 47 | // Serial.println(rtc.getDate(true)); // (String) Sunday, January 17 2021 48 | // Serial.println(rtc.getDateTime()); // (String) Sun, Jan 17 2021 15:24:38 49 | // Serial.println(rtc.getDateTime(true)); // (String) Sunday, January 17 2021 15:24:38 50 | // Serial.println(rtc.getTimeDate()); // (String) 15:24:38 Sun, Jan 17 2021 51 | // Serial.println(rtc.getTimeDate(true)); // (String) 15:24:38 Sunday, January 17 2021 52 | // 53 | // Serial.println(rtc.getMicros()); // (long) 723546 54 | // Serial.println(rtc.getMillis()); // (long) 723 55 | // Serial.println(rtc.getEpoch()); // (long) 1609459200 56 | // Serial.println(rtc.getSecond()); // (int) 38 (0-59) 57 | // Serial.println(rtc.getMinute()); // (int) 24 (0-59) 58 | // Serial.println(rtc.getHour()); // (int) 3 (0-12) 59 | // Serial.println(rtc.getHour(true)); // (int) 15 (0-23) 60 | // Serial.println(rtc.getAmPm()); // (String) pm 61 | // Serial.println(rtc.getAmPm(true)); // (String) PM 62 | // Serial.println(rtc.getDay()); // (int) 17 (1-31) 63 | // Serial.println(rtc.getDayofWeek()); // (int) 0 (0-6) 64 | // Serial.println(rtc.getDayofYear()); // (int) 16 (0-365) 65 | // Serial.println(rtc.getMonth()); // (int) 0 (0-11) 66 | // Serial.println(rtc.getYear()); // (int) 2021 67 | 68 | // Serial.println(rtc.getLocalEpoch()); // (long) 1609459200 epoch without offset 69 | Serial.println(rtc.getTime("%A, %B %d %Y %H:%M:%S")); // (String) returns time with specified format 70 | // formating options http://www.cplusplus.com/reference/ctime/strftime/ 71 | 72 | 73 | struct tm timeinfo = rtc.getTimeStruct(); 74 | //Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); // (tm struct) Sunday, January 17 2021 07:24:38 75 | 76 | delay(1000); 77 | } 78 | -------------------------------------------------------------------------------- /exemple/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | -------------------------------------------------------------------------------- /exemple/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 9 | 186 | -------------------------------------------------------------------------------- /exemple/index3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 208 | -------------------------------------------------------------------------------- /exemple/index4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /exemple/index5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /exemple/setime/setime/setime.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | ESP32Time rtc; 5 | //ESP32Time rtc(3600); // offset in seconds GMT+1 6 | 7 | BLEService service("1ce76320-2d32-41af-b4c4-46836ea7a62a"); // Bluetooth® Low Energy LED Service 8 | BLECharacteristic dateCharacteristic("ad804469-19ec-406a-b949-31ae17e43813", BLERead | BLENotify | BLEWrite, 8); 9 | BLECharacteristic lightCharacteristic("947aad02-c25d-11ed-afa1-0242ac120002", BLERead | BLENotify | BLEWrite , 4); 10 | BLECharacteristic doorCharacteristic("c3773399-b755-4e30-9160-bed203fae718", BLERead | BLENotify | BLEWrite , 2); 11 | BLECharacteristic doorCloseCharacteristic("e011ba0e-84c5-4e83-8648-f3e2660c44b0", BLERead | BLENotify | BLEWrite , 4); 12 | BLECharacteristic doorOpenCharacteristic("cc959fff-4f84-4d08-a720-9d9156a48ed5", BLERead | BLENotify | BLEWrite , 4); 13 | 14 | //badge 15 | uint8_t ble_value = 0x0; 16 | int analogValue = 500; 17 | int minValue = analogValue; 18 | int maxValue = analogValue; 19 | 20 | //settings door 21 | int doorWantedStatus = 0; 22 | int doorNbTurn = 1; 23 | 24 | //settings close 25 | int doorCloseMode = 0; 26 | int doorCloseLightThreshold = -1; 27 | int doorCloseTimeH = -1; 28 | int doorCloseTImeM = -1; 29 | 30 | //settings open 31 | int doorOpenMode = 0; 32 | int doorOpenLightThreshold = -1; 33 | int doorOpenTimeH = -1; 34 | int doorOpenTImeM = -1; 35 | 36 | 37 | void setup() { 38 | Serial.begin(9600); 39 | rtc.setTime(1609459200); 40 | while (!Serial); 41 | 42 | // begin initialization 43 | if (!BLE.begin()) { 44 | Serial.println("starting Bluetooth® Low Energy module failed!"); 45 | while (1); 46 | } 47 | 48 | // set advertised local name and service UUID: 49 | BLE.setLocalName("COOP-DOOR"); 50 | BLE.setAdvertisedService(service); 51 | service.addCharacteristic(dateCharacteristic); 52 | service.addCharacteristic(lightCharacteristic); 53 | service.addCharacteristic(doorCharacteristic); 54 | service.addCharacteristic(doorCloseCharacteristic); 55 | service.addCharacteristic(doorOpenCharacteristic); 56 | BLE.addService(service); 57 | dateCharacteristic.writeValue(0); 58 | lightCharacteristic.writeValue(0); 59 | doorCharacteristic.writeValue(0); 60 | 61 | 62 | // start advertising 63 | BLE.advertise(); 64 | 65 | Serial.println("BLE LED Peripheral"); 66 | } 67 | 68 | void loop() { 69 | // listen for Bluetooth® Low Energy peripherals to connect: 70 | BLEDevice central = BLE.central(); 71 | 72 | // if a central is connected to peripheral: 73 | if (central) { 74 | Serial.print("Connected to central: "); 75 | // print the central's MAC address: 76 | Serial.println(central.address()); 77 | 78 | // while the central is still connected to peripheral: 79 | while (central.connected()) { 80 | // if the remote device wrote to the characteristic, 81 | // use the value to control the LED: 82 | delay(500); 83 | 84 | manageDate(); 85 | manageLight(); 86 | manageSettingsDoor(); 87 | manageSettingsClose(); 88 | manageSettingsOpen(); 89 | 90 | 91 | 92 | } 93 | 94 | // when the central disconnects, print it out: 95 | Serial.print(F("Disconnected from central: ")); 96 | Serial.println(central.address()); 97 | } 98 | 99 | 100 | 101 | 102 | 103 | } 104 | 105 | void manageSettingsOpen(){ 106 | if (doorOpenCharacteristic.written() ) { 107 | Serial.println("update Door Open settings"); 108 | Serial.print(doorOpenCharacteristic.value()[0]); 109 | Serial.print(";"); 110 | Serial.print(doorOpenCharacteristic.value()[1]); 111 | Serial.print(";"); 112 | Serial.print(doorOpenCharacteristic.value()[2]); 113 | Serial.print(";"); 114 | Serial.println(doorOpenCharacteristic.value()[3]); 115 | doorOpenMode = doorOpenCharacteristic.value()[0]; 116 | doorOpenLightThreshold = doorOpenCharacteristic.value()[1]; 117 | doorOpenTimeH = doorOpenCharacteristic.value()[2]; 118 | doorOpenTImeM = doorOpenCharacteristic.value()[3]; 119 | 120 | }else{ 121 | //todo 122 | } 123 | } 124 | 125 | void manageSettingsClose(){ 126 | if (doorCloseCharacteristic.written() ) { 127 | Serial.println("update Door Close settings"); 128 | Serial.print(doorCloseCharacteristic.value()[0]); 129 | Serial.print(";"); 130 | Serial.print(doorCloseCharacteristic.value()[1]); 131 | Serial.print(";"); 132 | Serial.print(doorCloseCharacteristic.value()[2]); 133 | Serial.print(";"); 134 | Serial.println(doorCloseCharacteristic.value()[3]); 135 | doorCloseMode = doorCloseCharacteristic.value()[0]; 136 | doorCloseLightThreshold = doorCloseCharacteristic.value()[1]; 137 | doorCloseTimeH = doorCloseCharacteristic.value()[2]; 138 | doorCloseTImeM = doorCloseCharacteristic.value()[3]; 139 | 140 | }else{ 141 | //todo 142 | } 143 | } 144 | 145 | 146 | void manageSettingsDoor(){ 147 | if (doorCharacteristic.written() ) { 148 | Serial.println("update Door"); 149 | Serial.print(doorCharacteristic.value()[0]); 150 | Serial.print(";"); 151 | Serial.println(doorCharacteristic.value()[1]); 152 | }else{ 153 | //todo 154 | } 155 | } 156 | 157 | void manageLight(){ 158 | if (lightCharacteristic.written() && lightCharacteristic.value()[3] != 0x00) { 159 | analogValue = random(10, 1000); 160 | minValue = analogValue; 161 | maxValue = analogValue; 162 | Serial.println("reset light"); 163 | 164 | 165 | } else { 166 | analogValue = random(10, 1000); 167 | minValue = min(analogValue, minValue); 168 | maxValue = max(analogValue, maxValue); 169 | } 170 | Serial.print(" value "); 171 | Serial.print(analogValue); 172 | Serial.print(" minValue "); 173 | Serial.print(minValue); 174 | Serial.print(" maxValue "); 175 | Serial.print(maxValue); 176 | Serial.println(""); 177 | float divider = 1000 / 255.0; //1000 max allowed value, 255 max byte value 178 | uint8_t currentValue = analogValue / divider; 179 | uint8_t scaledMinValue = minValue / divider; 180 | uint8_t scaledMaxValue = maxValue / divider; 181 | 182 | uint8_t ble_value_array[4] = {currentValue, scaledMinValue, scaledMaxValue, 0x00 }; 183 | 184 | // Write the array to the characteristic 185 | lightCharacteristic.writeValue(ble_value_array, 4); 186 | 187 | 188 | } 189 | 190 | 191 | 192 | 193 | 194 | void manageDate() { 195 | if (dateCharacteristic.written()) { 196 | Serial.println("Date update"); 197 | long xx = getLongFromBytes(dateCharacteristic.value()); 198 | Serial.println(xx); 199 | rtc.setTime(xx); 200 | Serial.println(rtc.getEpoch()); 201 | 202 | 203 | } else { 204 | Serial.println(rtc.getEpoch()); 205 | byte* tmpDate = getBytesFromLong(rtc.getEpoch()); 206 | 207 | dateCharacteristic.writeValue(tmpDate, 8); 208 | delete[] tmpDate; 209 | } 210 | 211 | } 212 | 213 | 214 | byte* getBytesFromLong(long x ) { 215 | byte* bytes = new byte[8]; 216 | for (int i = 0; i < 8; i++) { 217 | bytes[i] = x & 0xff; 218 | x = (x - bytes[i]) / 256; 219 | } 220 | return bytes; 221 | 222 | } 223 | 224 | long getLongFromBytes(const byte* bytes) { 225 | long result = 0; 226 | for (int i = 7; i >= 0; i--) { 227 | result = (result * 256) + bytes[i]; 228 | } 229 | return result; 230 | } 231 | --------------------------------------------------------------------------------