├── .extra └── NOTES.md ├── .gitignore ├── 01-intro-to-iot └── 01-introduction-to-iot.pdf ├── 02-hardware-platforms ├── 02-hardware-platforms.pdf ├── Exercises.md ├── GPIO_PWM.png ├── Prerequisites.md ├── README.md ├── divider.sch ├── esp8266-wemos-d1-mini-pinout.png ├── nodemcu_0.9.png ├── nodemcu_1.0_v2.png └── src │ ├── 01_HelloWorld │ └── 01_HelloWorld.ino │ ├── 02_Blink │ ├── README.md │ └── images │ │ ├── breadboard.png │ │ ├── breadboard_simple.png │ │ ├── olimex_esp32.png │ │ ├── rgb.png │ │ └── rgb_schematic.png │ ├── 04_Interrupts │ └── 04_Interrupts.ino │ ├── 05_Watchdog │ └── 05_Watchdog.ino │ ├── 06_SPIFFS │ └── 06_SPIFFS.ino │ ├── 07_DUALCORE │ ├── dual_core_semaphore │ │ └── dual_core_semaphore.ino │ └── dual_core_template │ │ └── dual_core_template.ino │ └── 08_SerialTest │ └── 08_SerialTest.ino ├── 03-sensors ├── 03-sensors.pdf ├── CM1106.md ├── README.md └── src │ └── i2cscanner │ └── i2cscanner.ino ├── 04-displays-and-actuators ├── 04-displays-actuators.pdf ├── NeoPixelBar.ino ├── NeoPixeslFmi22.ino ├── SerialTest.ino ├── excercise.md └── src │ ├── Buzzer_PWM │ └── Buzzer_PWM.ino │ ├── Buzzer_PWM_advanced │ └── Buzzer_PWM_advanced.ino │ ├── Buzzer_tone │ └── Buzzer_tone.ino │ ├── FastLedNeoPixelRing │ ├── FastLedWS2812Ring.md │ ├── NeoPixelRingWS2812.ino │ └── images │ │ ├── ModulesConnection.png │ │ ├── NeoPixelRingSchema.png │ │ ├── PixelRingPinout.jpg │ │ ├── esp32.png │ │ ├── fastLedLib.png │ │ ├── together.png │ │ └── ws2812-front.png │ ├── HappyBirthday │ └── HappyBirthday.ino │ ├── LiquidCrystal_PCF8574 │ └── LiquidCrystal_PCF8574.ino │ ├── old_stuff │ ├── PCD8544 │ │ └── PCD8544.ino │ ├── ST7789_example │ │ └── ST7789_example.ino │ ├── si7021 │ │ └── si7021.ino │ └── ssd1306_128x64_spi │ │ └── ssd1306_128x64_spi.ino │ ├── servo │ ├── images │ │ ├── esp32.png │ │ ├── library_esp32.png │ │ ├── olimex_esp32.png │ │ ├── servo.png │ │ ├── servo_schematic.png │ │ ├── together.png │ │ └── wires_connections.png │ ├── servo.ino │ └── servo.md │ └── stepper_motor │ ├── images │ ├── ULN2003.png │ ├── ULN2003_pinout.png │ ├── olimex_esp32.png │ ├── sample.jpg │ ├── schematic_stepper.png │ ├── stepper.jpg │ ├── stepper_1.jpg │ └── stepper_motor_schem.png │ ├── stepper_motor.ino │ └── stepper_motor.md ├── 05-sensors-displays-exercise ├── CM1106_I2C │ └── CM1106_I2C.ino ├── Exercises.md ├── GY_521 │ └── GY_521.ino ├── MQ2 │ └── MQ2.ino ├── SGP40 │ └── SGP40.ino └── ssd1306_128x32_i2c │ └── ssd1306_128x32_i2c.ino ├── 06-connectivity-1 ├── Connectivity1.pdf ├── Exercises.md ├── board_name.png └── src │ ├── 01_OneWire │ └── README.md │ ├── 02_BLE_heartrate │ └── 02_BLE_heartrate.ino │ ├── 04_LoraModuleClient │ └── 04_LoraModuleClient.ino │ ├── BLE_server │ └── BLE_server.ino │ ├── DHT_Unified_Sensor │ └── DHT_Unified_Sensor.ino │ ├── DS18x20_OneWire │ └── DS18x20_OneWire.ino │ ├── DS18x20_multiple │ └── DS18x20_multiple.ino │ ├── ESP-Now │ ├── espnow-receiver.ino │ ├── espnow-transmitter.ino │ └── mac-scanner.ino │ ├── hc-12_receiver │ └── hc-12_receiver.ino │ └── hc-12_transmitter │ └── hc-12_transmitter.ino ├── 07-connectivity-2 ├── Connectivity2.pdf ├── README.md └── src │ ├── 01_WIFI_STA │ └── 01_WIFI_STA.ino │ ├── 02_WIFI_AP │ └── 02_WIFI_AP.ino │ ├── 03_HTTP_Server │ └── 03_HTTP_Server.ino │ ├── 04_HTTP_Client │ └── 04_HTTP_Client.ino │ ├── 05_PubSubClient │ └── 05_PubSubClient.ino │ ├── 06_ArduinoMQTT_qos1 │ └── 06_ArduinoMQTT_qos1.ino │ └── old │ ├── HttpServer │ └── HttpServer.ino │ ├── mosquitto │ ├── mosquitto.conf │ ├── mosquitto.yml │ └── passwd │ └── mosquitto_examples.md ├── 08-power-management ├── 08-power management.pdf ├── deep_sleep │ ├── deep_sleep.ino │ ├── deep_sleep.md │ └── images │ │ └── deep_sleep_touch.png └── sleep_modes │ ├── images │ ├── power_modes.png │ └── wiring.jpg │ ├── power_modes.png │ ├── sleep_modes.ino │ └── sleep_modes.md ├── 09-security ├── README.md ├── Security.pdf ├── mosquitto.org.crt └── src │ ├── 01_HTTP_W_WiFiClientSecure │ ├── 01_HTTP_W_WiFiClientSecure.ino │ └── ISRGRootX1_ОМ.pem │ ├── 02_MQTTS │ ├── 02_MQTTS.ino │ └── mosquitto.org.crt │ ├── 03_OAuth_Device_Flow │ ├── 03_OAuth_Device_Flow.ino │ └── ISRGRootX1.pem │ └── old │ └── 04_WifiProbing │ ├── 04_WifiProbing.ino │ ├── Notes.h │ ├── functions.h │ └── structures.h ├── 10-device-management ├── Device Management.pdf ├── README.md ├── divider_simulation.png ├── src │ ├── 01_AnalogVoltageMeasurement │ │ └── 01_AnalogVoltageMeasurement.ino │ ├── 02_WebUpdater │ │ └── 02_WebUpdater.ino │ ├── 03_WiFiManager_simple │ │ └── 03_WiFiManager_simple.ino │ ├── 04_WiFiManager_httpserver │ │ └── 04_WiFiManager_httpserver.ino │ ├── 05_DetectResetReason │ │ └── 05_DetectResetReason.ino │ ├── 06_WiFiProvisioner │ │ ├── WiFiProvisioner_simple.ino │ │ ├── WiFiProvisioner_simple.md │ │ └── images │ │ │ ├── wifiprov.png │ │ │ └── wifiprov_init.png │ ├── 07_core_temperature │ │ ├── core_temperature.ino │ │ └── core_temperature.md │ ├── 08_supply_voltage_measurement │ │ ├── supply_voltage_measurement.ino │ │ └── supply_voltage_measurement.md │ └── 09_OTA_server │ │ ├── images │ │ ├── export_scetch.png │ │ ├── ota_update_file.png │ │ ├── show_folder.png │ │ └── update.png │ │ ├── ota_server.ino │ │ └── ota_server.md └── thinx-firmware-esp8266-ino.zip ├── 11-data-management-and-analytics ├── Data Management & Analytics.pdf ├── README.md └── notebooks │ ├── Pandas_timeseries.ipynb │ ├── Parquet.ipynb │ ├── TimeSeriesVisualization.ipynb │ ├── poetry.lock │ └── pyproject.toml ├── 15-whats-new-in-iot ├── Blockchain.pdf ├── PowerManagementAndExistingTech.pdf ├── README.md ├── WiFi_sensing.pdf └── energy-harvesting-IoT-su.pdf ├── README.md ├── brainstorming2020.md ├── images └── iot-on-youtube.png └── scripts └── convert.py /.extra/NOTES.md: -------------------------------------------------------------------------------- 1 | # Some extra materials 2 | 3 | https://interrupt.memfault.com/blog/firmware-watchdog-best-practices 4 | 5 | https://dtn7.github.io/assets/hoechst2020lora.pdf 6 | 7 | https://www.slideshare.net/AnthonyChow5/mqtt-security 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.ppt* 2 | .ipynb_checkpoints -------------------------------------------------------------------------------- /01-intro-to-iot/01-introduction-to-iot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/01-intro-to-iot/01-introduction-to-iot.pdf -------------------------------------------------------------------------------- /02-hardware-platforms/02-hardware-platforms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/02-hardware-platforms.pdf -------------------------------------------------------------------------------- /02-hardware-platforms/Exercises.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | Connect the board to the PC and do the exercises, listed in the `src` folder. Start with `HelloWorld`. 3 | 4 | # Optional exercises 5 | ## Dual core 6 | The `07_DUALCORE` exercise touches some advanced features. The ESP32 has two available cores that share the heap (~290KB). By default, the `loop()` function runs on core 1. Using some built-in functions, we can set as many as we want tasks on any core. Most notably, we can run a high-memory high-performance task on core 0, and run our networking/error-handling code on core 1 to avoid bottlenecks. 7 | 8 | - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html 9 | - https://www.freertos.org/a00113.html 10 | - https://www.freertos.org/RTOS_Task_Notification_As_Counting_Semaphore.html 11 | 12 | ## Serial comm 13 | The `08_SerialTest` exercise demonstrates incoming serial communication. You have to write commands in the serial monitor and they will be executed by the board. 14 | -------------------------------------------------------------------------------- /02-hardware-platforms/GPIO_PWM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/GPIO_PWM.png -------------------------------------------------------------------------------- /02-hardware-platforms/Prerequisites.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 1. Install [Arduino IDE](https://www.arduino.cc/en/software) 2.3.4 3 | 2. Install [ESP32 Development Kit](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html) 4 | 3. Some boards require USB to serial drivers. To determine which chip you have, open device manager, plug the board and look what appears under `Ports (COM & LPT)`. On linux you may have to tail the syslog to determine the device. Then download the driver from the manufacturer's site. Known drivers are: 5 | - [Silabs CP2102](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads) 6 | 7 | 8 | # Board selection 9 | Open the Arduino IDE, plug your board and select the board from the 10 | `Tools > Board > esp32 >` **OLIMEX-ESP32-DevKit-Lipo** 11 | 12 | # Troubleshooting 13 | ## ESP32: Upload not working 14 | 1. You tried unplugging and plugging the board back right :) ? 15 | 2. On some boards, you have to hold the `BOOT` button for a while after triggering the upload from the IDE. After upload starts, you can release it. 16 | 3. Sometimes, upload speeds higher than 256000 do not work reliably (e.g. depending on the USB cable quality). 17 | 4. Try stopping your antivirus and see if it makes a difference (don't forget to turn it back on). 18 | - If this is the problem, you may have to whitelist some of the Arduino executables, or install Arduino in a folder outside e.g. `C:\Program Files (x86)` 19 | 6. Do a fresh reinstall 20 | - Uninstall Arduino 21 | - Manually delete its data folder 22 | - Windows: `C:\Users\(username)\AppData\Roaming\Arduino15` or `C:\Users\(username)\AppData\Local\Arduino15` 23 | - Linux: `/home/(username)/.arduino15` 24 | - Mac: `/Users/(username)/Library/Arduino15` 25 | - Install again 26 | 7. Try to [set both outputs to verbose mode](https://forum.arduino.cc/index.php?topic=615560.0) and look carefuly at the output. 27 | 8. See if [turning off the compile cache](https://forum.arduino.cc/index.php?topic=686705.0) solves the problem. 28 | 29 | ## ESP32: no output in serial monitor in Windows 10 30 | For some reason i had to go to Device Manager -> Ports and then in the COM Port for the connected device. Then go to Properties -> Port Settings -> Advanced, and set the COM Port number to something else (e.g. COM 19). Then I had to unplug the device and plug it again and it was working and reverting the port back to the original it was working again 31 | 32 | ## Serial Port under Linux 33 | This post explains what needs to be done to enable the com port under linux: http://forum.vair-monitor.com/showthread.php?tid=1&pid=41#pid41 34 | * ESP and MacOS BigSur 11.2.3 - pyserial or esptool directories not found next to this upload.py tool. 35 | ![](https://user-images.githubusercontent.com/492455/111058955-b582a480-849a-11eb-853b-f692e5d1e226.png) 36 | 37 | 38 | # Optional Drivers 39 | 1. (optional) Install drivers (Mac) for the CP2102 Usb2Serial chip: [http://vair-monitor.com/drivers/](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads) 40 | 41 | -------------------------------------------------------------------------------- /02-hardware-platforms/README.md: -------------------------------------------------------------------------------- 1 | # Hardware platforms 2 | -------------------------------------------------------------------------------- /02-hardware-platforms/divider.sch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <.DC DCsim 1 90 330 0 47 0 0 "26.85" 0 "0.001" 0 "1 pA" 0 "1 uV" 0 "no" 0 "150" 0 "no" 0 "none" 0 "CroutLU" 0> 22 | 23 | 24 | 25 | 26 | <320 360 320 400 "" 0 0 0 ""> 27 | <320 400 460 400 "" 0 0 0 ""> 28 | <460 400 460 420 "" 0 0 0 ""> 29 | <600 380 600 400 "" 0 0 0 ""> 30 | <460 400 600 400 "" 0 0 0 ""> 31 | <320 180 320 300 "" 0 0 0 ""> 32 | <320 180 600 180 "" 0 0 0 ""> 33 | <600 180 600 240 "" 0 0 0 ""> 34 | <600 300 600 320 "mid_voltage" 420 260 9 ""> 35 | 36 | 37 | 38 | <"mid_voltage.V" #0000ff 0 3 1 0 0> 39 | <"V1.I" #0000ff 0 3 1 0 0> 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /02-hardware-platforms/esp8266-wemos-d1-mini-pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/esp8266-wemos-d1-mini-pinout.png -------------------------------------------------------------------------------- /02-hardware-platforms/nodemcu_0.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/nodemcu_0.9.png -------------------------------------------------------------------------------- /02-hardware-platforms/nodemcu_1.0_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/nodemcu_1.0_v2.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/01_HelloWorld/01_HelloWorld.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | Serial.begin(115200L); 3 | } 4 | 5 | void loop() { 6 | Serial.println("Hello world"); 7 | delay(1000); 8 | } 9 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/README.md: -------------------------------------------------------------------------------- 1 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) which does not have builtin button and builtin LED, so you have to build our own simple schematic with external parts and breadboard to make examples using buttons and LEDs. 2 | 3 | You already have some components to use - **push buttons, cables, LED, breadboard**. You can check here more details how to use bradboard: https://youtube.com/shorts/05ZrbtwUzMk?si=gIbFwLqku33tUpSa 4 | 5 | ## RGB LED 6 | You got RGB (Reg Green Blue) LED (light emitting diode), that have 3 separate colors in a single LED package and the colors can be mixed if two or more colors are turned on simultaneously. These LEDs have common anode, that means they have one common connection which is positive +3.3V. If you want to turn a color on, you need to connect the color pin to negative voltage bus. Here is a picture to explain it: 7 | 8 | ![alt text](images/rgb.png) 9 | 10 | ## Schematic and connections 11 | 12 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 13 | 14 | - Schematic is [here](images/rgb_schematic.png). 15 | 16 | - This is how the components should be connected on the breadboard (please note the ESP32 board looks different than the red Olimex but the pins are the same): 17 | 18 | ![alt text](images/breadboard.png) 19 | 20 | For simplicity the ESP32 board can be connected directly on the breadboard and only one cable is needed to connect the anode of the LED (+3.3V), like on this picture. Just manually twist the anode of the LED (the longest leg) and connect it with a male-female cable to bradboard. 21 | 22 | ![alt text](images/breadboard_simple.png) 23 | 24 | ## Code to Run (Arduino Sketches) 25 | 26 | 1. Run this sketch in Arduino IDE, compile it and and upload it to the board, it will cycle the 3 colors with 1 sec interval: 27 | 28 | ```cpp 29 | // Define PINs where the R, G and B colors are connected 30 | const int blueLED = 26; 31 | const int greenLED = 25; 32 | const int redLED = 27; 33 | // Define pin where the button is connected 34 | const int button = 14; 35 | 36 | // the setup function runs once when you press reset or power the board 37 | void setup() { 38 | // initialize digital pin LED_BUILTIN as an output. 39 | pinMode(blueLED, OUTPUT); // Blue LED 40 | pinMode(greenLED, OUTPUT); // Green LED 41 | pinMode(redLED, OUTPUT); // Red LED 42 | pinMode(button, INPUT_PULLUP); // Button pin, it have internal pullup resistor enabled so we don't have to add external one 43 | } 44 | 45 | // the loop function runs over and over again forever 46 | void loop() { 47 | // These LEDs are having common anode (positive voltage or +), thus turing pin LOW (negative voltage or -) will turn it ON 48 | digitalWrite(blueLED, LOW); // turn the LED on 49 | delay(1000); // wait for a second 50 | digitalWrite(blueLED, HIGH); // turn the LED off by turning positive voltage 51 | digitalWrite(greenLED, LOW); // turn the LED on by turining negative voltage 52 | delay(1000); // wait for a second 53 | digitalWrite(greenLED, HIGH); // turn the LED off by turning positive voltage 54 | digitalWrite(redLED, LOW); // turn the LED on by turining negative voltage 55 | delay(1000); // wait for a second 56 | digitalWrite(redLED, HIGH); // turn the LED off by turning positive voltage 57 | } 58 | ``` 59 | 60 | 2. Make the loop a bit more advanced by reading the button and run the color cycle only when the button is pressed: 61 | ```cpp 62 | void loop() { 63 | int buttonstate = digitalRead(button); 64 | if (buttonstate == LOW) { 65 | // These LEDs are having common anode (positive voltage or +), thus turing pin LOW (negative voltage or -) will turn it ON 66 | digitalWrite(blueLED, LOW); // turn the LED on 67 | delay(1000); // wait for a second 68 | digitalWrite(blueLED, HIGH); // turn the LED off by turning positive voltage 69 | digitalWrite(greenLED, LOW); // turn the LED on by turining negative voltage 70 | delay(1000); // wait for a second 71 | digitalWrite(greenLED, HIGH); // turn the LED off by turning positive voltage 72 | digitalWrite(redLED, LOW); // turn the LED on by turining negative voltage 73 | delay(1000); // wait for a second 74 | digitalWrite(redLED, HIGH); // turn the LED off by turning positive voltage 75 | } else { 76 | digitalWrite(redLED, HIGH); 77 | digitalWrite(blueLED, HIGH); 78 | digitalWrite(greenLED, HIGH); 79 | } 80 | } 81 | ``` 82 | 83 | 3. Now that you know how the LED blinker works, you can play write some sketch to mix colors or do some other combination with the button. Maybe traffic light... :) 84 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/images/breadboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/src/02_Blink/images/breadboard.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/images/breadboard_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/src/02_Blink/images/breadboard_simple.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/images/olimex_esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/src/02_Blink/images/olimex_esp32.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/images/rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/src/02_Blink/images/rgb.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/02_Blink/images/rgb_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/02-hardware-platforms/src/02_Blink/images/rgb_schematic.png -------------------------------------------------------------------------------- /02-hardware-platforms/src/04_Interrupts/04_Interrupts.ino: -------------------------------------------------------------------------------- 1 | #define FLASH_BUTTON 14 2 | 3 | volatile int unprocessed_interrupts; 4 | 5 | void setup() { 6 | 7 | pinMode(FLASH_BUTTON,INPUT_PULLUP); 8 | attachInterrupt(digitalPinToInterrupt(FLASH_BUTTON), handleInterrupt, FALLING); 9 | 10 | Serial.begin(115200L); 11 | } 12 | 13 | ICACHE_RAM_ATTR void handleInterrupt() { 14 | unprocessed_interrupts++; 15 | } 16 | 17 | void loop() { 18 | 19 | Serial.println("Processing interrupts: " + String(unprocessed_interrupts)); 20 | unprocessed_interrupts = 0; 21 | 22 | delay(3000); 23 | } 24 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/05_Watchdog/05_Watchdog.ino: -------------------------------------------------------------------------------- 1 | #include "esp_system.h" 2 | 3 | const int TIMEOUT_MS = 2000; 4 | 5 | esp_timer_handle_t timer; 6 | 7 | void IRAM_ATTR timerTriggered(void* arg) { 8 | esp_restart(); 9 | } 10 | 11 | void setup() { 12 | Serial.begin(115200); 13 | 14 | // Create a timer 15 | const esp_timer_create_args_t timer_args = { 16 | .callback = &timerTriggered, 17 | .arg = NULL, 18 | .name = "watchdog_timer" 19 | }; 20 | esp_timer_create(&timer_args, &timer); 21 | 22 | // Start the timer 23 | esp_timer_start_once(timer, TIMEOUT_MS * 1000); 24 | } 25 | 26 | void loop() { 27 | Serial.println("In main loop"); 28 | delay(TIMEOUT_MS * 2); 29 | esp_timer_stop(timer); 30 | esp_timer_start_once(timer, TIMEOUT_MS * 1000); 31 | } 32 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/06_SPIFFS/06_SPIFFS.ino: -------------------------------------------------------------------------------- 1 | #include "SPIFFS.h" 2 | 3 | void setup() { 4 | 5 | Serial.begin(115200); 6 | 7 | if (!SPIFFS.begin(true)) { 8 | Serial.println("SPIFFS Error"); 9 | return; 10 | } 11 | 12 | File testFile = SPIFFS.open("/test.txt", FILE_WRITE); 13 | 14 | if (!testFile) { 15 | Serial.println("Can't open file"); 16 | return; 17 | } 18 | 19 | Serial.println("Writing to file ..."); 20 | if (!testFile.print("TEST")) { 21 | Serial.println("Write failure"); 22 | return; 23 | } 24 | testFile.close(); 25 | 26 | 27 | Serial.println("List files: "); 28 | File root = SPIFFS.open("/"); 29 | File file = root.openNextFile(); 30 | 31 | while(file){ 32 | Serial.println(file.name()); 33 | file = root.openNextFile(); 34 | } 35 | } 36 | 37 | void loop() {} 38 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/07_DUALCORE/dual_core_semaphore/dual_core_semaphore.ino: -------------------------------------------------------------------------------- 1 | void loop2(void* param); 2 | 3 | /* Semaphores can be set up with xSemaphore... functions, too. */ 4 | struct shared_data 5 | { 6 | constexpr static uint8_t capacity = 64; 7 | char str[capacity]; 8 | int locked = 0; 9 | 10 | void lock() { ++locked; } 11 | void unlock() { locked = (locked == 0) ? 0 : locked - 1; } 12 | void clearbuff() { memset(str, 0, shared_data::capacity); } 13 | } sd; 14 | 15 | void setup() 16 | { 17 | Serial.begin(115200); 18 | xTaskCreatePinnedToCore(loop2, "loop2", 4096, nullptr, 2, nullptr, 0); 19 | } 20 | 21 | void loop() 22 | { 23 | while (sd.locked) 24 | { 25 | ; 26 | } 27 | sd.lock(); 28 | /* If result isn't empty, display it. */ 29 | if(*sd.str != '\0') 30 | { 31 | Serial.printf("%s\n", sd.str); 32 | /* Reset the buffer (not necessary, just to avoid spam). */ 33 | sd.clearbuff(); 34 | } 35 | sd.unlock(); 36 | 37 | /* 38 | While the other core works, we can probe for new results rapidly, 39 | and run networking/bookkeeping without interrupting it. 40 | The semaphore covers the *unlikely* case of simultaneous access. 41 | */ 42 | delay(50); 43 | } 44 | 45 | void loop2(void* param) 46 | { 47 | while (true) 48 | { 49 | /* Simulate our computation that takes some time. */ 50 | delay(1800); 51 | 52 | /* Write results. */ 53 | while (sd.locked) 54 | { 55 | ; 56 | } 57 | sd.lock(); 58 | 59 | const char* msg = "Hello World!"; 60 | strcpy(sd.str, msg); 61 | 62 | 63 | sd.unlock(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/07_DUALCORE/dual_core_template/dual_core_template.ino: -------------------------------------------------------------------------------- 1 | void loop2(void* param); 2 | 3 | void setup() 4 | { 5 | Serial.begin(115200); 6 | 7 | /* xTaskCreatePinnedToCore( 8 | function address, 9 | task name, 10 | stack size (allocated on heap, 1024/2048/4096 is OK), 11 | function argument pointer, 12 | priority (loop() has 1 by default), 13 | task handle (not necessary), 14 | core number (loop() runs on 1 generally)); 15 | 16 | NB: We can put multiple tasks on any core. */ 17 | xTaskCreatePinnedToCore(loop2, "loop2", 1024, nullptr, 0, nullptr, 0); 18 | } 19 | 20 | void loop() 21 | { 22 | /* Core 1 code. */ 23 | } 24 | 25 | void loop2(void* param) 26 | { 27 | /* 28 | loop() also runs in a loop behind the scenes. 29 | Make loop2() run indefinitely as well. 30 | */ 31 | while (true) 32 | { 33 | /* loop2 code. */ 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /02-hardware-platforms/src/08_SerialTest/08_SerialTest.ino: -------------------------------------------------------------------------------- 1 | char line[200]; 2 | 3 | int readLine(int timeout) { 4 | unsigned long deadline = millis() + timeout; 5 | int i = 0; 6 | while (millis() < deadline) { 7 | if (Serial.available()) { 8 | line[i++] = (char) Serial.read(); 9 | if (line[i-1] == '\r') i--; 10 | else if (i == sizeof(line) - 1) break; 11 | else if (line[i-1] == '\n') {i--; break;} 12 | } 13 | } 14 | line[i] = 0; 15 | return i; 16 | } 17 | 18 | void setup() { 19 | Serial.begin(115200L); 20 | Serial.println("Serial test started"); 21 | } 22 | 23 | void loop() { 24 | if (readLine(1000) > 0) { 25 | Serial.print("Received: " ); 26 | Serial.println(line); 27 | String s = line; 28 | if (s == "restart") ESP.restart(); 29 | else if (s == "millis") Serial.println(millis()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /03-sensors/03-sensors.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/03-sensors/03-sensors.pdf -------------------------------------------------------------------------------- /03-sensors/CM1106.md: -------------------------------------------------------------------------------- 1 | example code 2 | https://github.com/jcomas/CM1106_UART 3 | -------------------------------------------------------------------------------- /03-sensors/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # VL53L0X - TOF Sensor 5 | 6 | Лазерен сензор за измерване на разстояние, между 20-1200 мм 7 | 8 | ## Install Driver 9 | 10 | * Adafruit_VL53L0X - -> Sketch -> Include Library -> Manage Libraries -> Search for "VL53L0X", install "Adafruit VL53L0X " 11 | 12 | ## Connection 13 | * VCC - 3.3v (3V3) 14 | * GND - GND (G) 15 | * SDA - 16 or any other 16 | * SCL - 17 or any other 17 | 18 | 19 | ## Run Example 20 | 21 | 1. Open Example from -> File / Examples / Adafriut VL53L0X / VL53L0X_continous 22 | 2. Adapt for correct I2C Pins, e.g. `Wire.begin(SDA, SCL) 23 | ``` 24 | void setup() { 25 | Serial.begin(115200); 26 | Wire.begin(21, 22); 27 | ``` 28 | 3. Run and enjoy 29 | 30 | 31 | # BME 280 / SI7021 / BMP280 32 | 33 | * BME280 vs BMP280 34 | image 35 | 36 | * SI7021 37 | image 38 | 39 | 40 | (За Si7021 - аналогично, пак трябва да се добави Wire.begin, но няма нужда да се специфицира адрес на сензора) 41 | ## Install Driver 42 | 43 | * BME280 Driver - -> Sketch -> Include Library -> Manage Libraries -> Search for "bme280", install "Adafruit BME280 Library" 44 | * BMP280 Driver - -> Sketch -> Include Library -> Manage Libraries -> Search for "bmp280", install "Adafruit BMP280 Library" 45 | * SI7021 Driver - -> Sketch -> Include Library -> Manage Libraries -> Search for "si7021", install "Adafruit SI7021 Library" 46 | 47 | 48 | ## Connection 49 | 50 | * VCC - 3.3v (3V3) 51 | * GND - GND (G) 52 | * SDA - 16 53 | * SCL - 17 54 | 55 | 56 | ## Run Example 57 | 58 | 1. Open Example from - File / Examples / Adafruit BME280 Library / bme280test 59 | 2. Adapt for ESP8266, and BME280 Breakout 60 | 61 | The sensor can have addresses 0x76 & 0x77, our breakout uses 0x76, the default for the library is 0x77. 62 | We need to call *Wire.begin(SDA, SCL)*, e.g. like Wire.begin(16, 17). Without it, the expected ports for I2C communication are different for each breakout board 63 | 64 | Make sure that you do not have 2 lines, only the one with the address is needed. The other breaks it 65 | ``` 66 | status = bme.begin() 67 | ... 68 | status = bme.begin(0x76) 69 | ``` 70 | 71 | ``` 72 | Serial.begin(9600); 73 | 74 | Wire.begin(16, 17); 75 | status = bme.begin(0x76); 76 | ``` 77 | _Note the serial baud rate in this example is 9600, so it needs to be changed in the serial monitor_ 78 | 79 | # Buttons 80 | 81 | Good tutorial for button debouncing, and explanation: https://esp32io.com/tutorials/esp32-button-debounce 82 | Defautl button on the board "BOOT" seems to be debounced. So to test it a wire between a pin and GND needs to be used 83 | -------------------------------------------------------------------------------- /03-sensors/src/i2cscanner/i2cscanner.ino: -------------------------------------------------------------------------------- 1 | // -------------------------------------- 2 | // i2c_scanner 3 | // 4 | // Version 1 5 | // This program (or code that looks like it) 6 | // can be found in many places. 7 | // For example on the Arduino.cc forum. 8 | // The original author is not know. 9 | // Version 2, Juni 2012, Using Arduino 1.0.1 10 | // Adapted to be as simple as possible by Arduino.cc user Krodal 11 | // Version 3, Feb 26 2013 12 | // V3 by louarnold 13 | // Version 4, March 3, 2013, Using Arduino 1.0.3 14 | // by Arduino.cc user Krodal. 15 | // Changes by louarnold removed. 16 | // Scanning addresses changed from 0...127 to 1...119, 17 | // according to the i2c scanner by Nick Gammon 18 | // https://www.gammon.com.au/forum/?id=10896 19 | // Version 5, March 28, 2013 20 | // As version 4, but address scans now to 127. 21 | // A sensor seems to use address 120. 22 | // Version 6, November 27, 2015. 23 | // Added waiting for the Leonardo serial communication. 24 | // 25 | // 26 | // This sketch tests the standard 7-bit addresses 27 | // Devices with higher bit address might not be seen properly. 28 | // 29 | 30 | #include 31 | 32 | 33 | void setup() 34 | { 35 | Wire.begin(21, 22); // SDA, SCL 36 | 37 | Serial.begin(115200); 38 | while (!Serial); // Leonardo: wait for serial monitor 39 | Serial.println("\nI2C Scanner"); 40 | } 41 | 42 | 43 | void loop() 44 | { 45 | byte error, address; 46 | int nDevices; 47 | 48 | Serial.println("Scanning..."); 49 | 50 | nDevices = 0; 51 | for(address = 1; address < 127; address++ ) 52 | { 53 | // The i2c_scanner uses the return value of 54 | // the Write.endTransmisstion to see if 55 | // a device did acknowledge to the address. 56 | Wire.beginTransmission(address); 57 | error = Wire.endTransmission(); 58 | 59 | if (error == 0) 60 | { 61 | Serial.print("I2C device found at address 0x"); 62 | if (address<16) 63 | Serial.print("0"); 64 | Serial.print(address,HEX); 65 | Serial.println(" !"); 66 | 67 | nDevices++; 68 | } 69 | else if (error==4) 70 | { 71 | Serial.print("Unknown error at address 0x"); 72 | if (address<16) 73 | Serial.print("0"); 74 | Serial.println(address,HEX); 75 | } 76 | } 77 | if (nDevices == 0) 78 | Serial.println("No I2C devices found\n"); 79 | else 80 | Serial.println("done\n"); 81 | 82 | delay(5000); // wait 5 seconds for next scan 83 | } 84 | -------------------------------------------------------------------------------- /04-displays-and-actuators/04-displays-actuators.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/04-displays-actuators.pdf -------------------------------------------------------------------------------- /04-displays-and-actuators/NeoPixelBar.ino: -------------------------------------------------------------------------------- 1 | // Connect IN /Data to GPIO2 or D4 on Nodemcu / Wemos 2 | // 3 | 4 | #include 5 | 6 | const uint16_t PixelCount = 6; // this example assumes 4 pixels, making it smaller will cause a failure 7 | const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 8 | 9 | 10 | #define Cred RgbColor(255, 0, 0) 11 | #define Cpink RgbColor(255, 0, 128) 12 | #define Clila RgbColor(255, 0, 255) 13 | #define Cviolet RgbColor(128, 0, 255) 14 | #define Cblue RgbColor(0, 0, 255) 15 | #define Cmblue RgbColor(0, 128, 255) 16 | #define Ccyan RgbColor(0, 255, 255) 17 | #define Cgreen RgbColor(0, 255, 0) 18 | #define Cyellow RgbColor(255, 255, 0) 19 | #define Corange RgbColor(255, 100, 0) 20 | #define Cwhite RgbColor(255, 255, 255) 21 | #define Cblack RgbColor(0) 22 | RgbColor allColors[] = {Cred, Clila, Cmblue, Cgreen, Cyellow, Corange}; 23 | 24 | // Uart method is good for the Esp-01 or other pin restricted modules 25 | // NOTE: These will ignore the PIN and use GPI02 pin 26 | NeoPixelBus strip(PixelCount, PixelPin); 27 | //NeoPixelBus strip(PixelCount, PixelPin); 28 | 29 | 30 | void setup() 31 | { 32 | Serial.begin(115200); 33 | while (!Serial); // wait for serial attach 34 | 35 | Serial.println(); 36 | Serial.println("Initializing..."); 37 | Serial.flush(); 38 | 39 | // this resets all the neopixels to an off state 40 | strip.Begin(); 41 | strip.Show(); 42 | 43 | 44 | Serial.println(); 45 | Serial.println("Running..."); 46 | } 47 | 48 | 49 | void loop() 50 | { 51 | 52 | for (int i=0; i < 6; i++) { 53 | RgbColor c = allColors[i]; 54 | c = RgbColor::LinearBlend(c, Cblack, 0.9F); 55 | strip.SetPixelColor(i, c); 56 | strip.Show(); 57 | delay(500); 58 | } 59 | delay(1000); 60 | 61 | Serial.println("Off ..."); 62 | for (int i=0; i < 6; i++) { 63 | strip.SetPixelColor(i, Cblack); 64 | strip.Show(); 65 | delay(100); 66 | } 67 | 68 | // delay(1000); 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /04-displays-and-actuators/NeoPixeslFmi22.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | 5 | const uint16_t PixelCount = 8; // this example assumes 4 pixels, making it smaller will cause a failure 6 | const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 7 | 8 | 9 | #define Cred RgbColor(255, 0, 0) 10 | #define Cpink RgbColor(255, 0, 128) 11 | #define Clila RgbColor(255, 0, 255) 12 | #define Cviolet RgbColor(128, 0, 255) 13 | #define Cblue RgbColor(0, 0, 255) 14 | #define Cmblue RgbColor(0, 128, 255) 15 | #define Ccyan RgbColor(0, 255, 255) 16 | #define Cgreen RgbColor(0, 255, 0) 17 | #define Cyellow RgbColor(255, 255, 0) 18 | #define Corange RgbColor(255, 100, 0) 19 | #define Cwhite RgbColor(255, 255, 255) 20 | #define Cblack RgbColor(0) 21 | RgbColor allColors[] = {Cred, Clila,Cviolet, Cmblue, Ccyan , Cgreen, Cyellow, Corange}; 22 | 23 | // Uart method is good for the Esp-01 or other pin restricted modules 24 | // NOTE: These will ignore the PIN and use GPI02 pin 25 | //NeoPixelBus strip(PixelCount, PixelPin); 26 | NeoPixelBus strip(PixelCount, PixelPin); 27 | //NeoPixelBus strip(PixelCount, PixelPin); 28 | 29 | 30 | void setup() 31 | { 32 | Serial.begin(115200); 33 | while (!Serial); // wait for serial attach 34 | 35 | Serial.println(); 36 | Serial.println("Initializing..."); 37 | Serial.flush(); 38 | 39 | // this resets all the neopixels to an off state 40 | strip.Begin(); 41 | strip.Show(); 42 | 43 | 44 | Serial.println(); 45 | Serial.println("Running..."); 46 | } 47 | 48 | 49 | void loop() 50 | { 51 | 52 | for (int i=0; i < PixelCount; i++) { 53 | RgbColor c = allColors[i]; 54 | c = RgbColor::LinearBlend(c, Cblack, 0.9F); 55 | strip.SetPixelColor(i, c); 56 | strip.Show(); 57 | delay(500); 58 | } 59 | delay(1000); 60 | 61 | Serial.println("Off ..."); 62 | for (int i=0; i < PixelCount; i++) { 63 | strip.SetPixelColor(i, Cblack); 64 | strip.Show(); 65 | delay(100); 66 | } 67 | 68 | // delay(1000); 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /04-displays-and-actuators/SerialTest.ino: -------------------------------------------------------------------------------- 1 | char line[200]; 2 | 3 | int readLine(int timeout) { 4 | unsigned long deadline = millis() + timeout; 5 | int i = 0; 6 | while (millis() < deadline) { 7 | if (Serial.available()) { 8 | line[i++] = (char) Serial.read(); 9 | if (line[i-1] == '\r') i--; 10 | else if (i == sizeof(line) - 1) break; 11 | else if (line[i-1] == '\n') {i--; break;} 12 | } 13 | } 14 | line[i] = 0; 15 | return i; 16 | } 17 | 18 | void setup() { 19 | Serial.begin(115200L); 20 | Serial.println("Serial test started"); 21 | } 22 | 23 | void loop() { 24 | if (readLine(1000) > 0) { 25 | Serial.print("Received: " ); 26 | Serial.println(line); 27 | String s = line; 28 | if (s == "restart") ESP.restart(); 29 | else if (s == "millis") Serial.println(millis()); 30 | } 31 | } -------------------------------------------------------------------------------- /04-displays-and-actuators/excercise.md: -------------------------------------------------------------------------------- 1 | # Random 2 | Location of default GPIO mappings for ESP8266 boards: c:\Users\I024148\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\variants\nodemcu\ 3 | 4 | # NeoPixel Test 5 | Documentation is here https://github.com/Makuna/NeoPixelBus/wiki, but is quite a LOT. 6 | 7 | For ESP32 amd Arduino328 it can be connected to almost any pin, for ESP8266, it works best on GPIO 2 (D4 on some boards) and GPIO 3 (used for Serial Input usually). When connected to other pins there may be issues with WiFi. This is why initialization is via 8 | 9 | Note: the drawback here is that GPIO2 on ESP8266 is pulled up/down during sketch upload, so NeoPixels may show some colors (usually Green) after sketch is uploaded 10 | For ESP32 there are no such issues detected 11 | 12 | **Connection** : 5V/VIN, GND, DIN -> [ANY] (ESP32) or D4 (ESP8266 GPIO2) 13 | 1. Install "NeoPixelBus by Makuna" library 14 | 2. Example: https://github.com/fmi/iot-course/blob/master/04-displays-and-actuators/NeoPixeslFmi22.ino 15 | 3. Some good example from the library is examples/NeopPixelBus by Makuna/animations/NeoPixelFunLoop (just set Pixelcount to the number of pixels - e.g. 8 or 16 depending on the LED Board. And adapt the "PixelPin" variable) 16 | 17 | 18 | # LiquidCrystal 19 | 1. Install "LiquidCrystal I2C" Library by Frank Brabander. There are a lot so find and select this one. It comes first 20 | 2. Note: Arduino 2.x is not able to open the examples from this library automatically. As they are .pde and not .ino. Therefore open them From: File -> Open -> Go to Documents/Arduino/libraries/LiquidCrystal I2C/examples. 21 | 4. Or in case of older Arduino version: Load example from `examples/INCOMPATIBLE/Liquid Crystal I2C/HelloWorld` or without "INCOMPATIBLE" (it says incompatible as the library does not state ESP32, but it uses just standard functionality so it is fine) 22 | 5. In the beginning of the sketch, provide the SDA,SCA pins that you are using via Wire.begin(16,17); (in case SDA=16, SCL=17). And connect to 5V and GND 23 | 6. Most likely you will need to turn the knob on the back clockwise to increase contrast until you see something 24 | 7. if nothing is shown, you may need to change the port for the display from 0x27 to 0x3F -> `LiquidCrystal_I2C lcd(0x3F,16,2);` 25 | 26 | ``` 27 | #include 28 | 29 | LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 30 | 31 | void setup() 32 | { 33 | 34 | Wire.begin(22,23); 35 | lcd.init(); // initialize the lcd 36 | 37 | ``` 38 | 39 | 40 | # Serial Input Test 41 | It is a bit tricky to handle Serial Input correctly and there wasn't a good example for this shipped with the ESP libraries, so here is one that can be embeded in other projects 42 | 43 | 1. Copy contents of this sketch https://github.com/fmi/iot-course/blob/master/04-displays-and-actuators/SerialTest.ino to a new sketch 44 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/Buzzer_PWM/Buzzer_PWM.ino: -------------------------------------------------------------------------------- 1 | #define BUZZER 13 // GPIO pin connected to the buzzer 2 | 3 | void setup() { 4 | pinMode(BUZZER, OUTPUT); 5 | } 6 | 7 | void loop() { 8 | for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) { 9 | analogWrite(BUZZER, dutyCycle); 10 | delay(15); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/Buzzer_PWM_advanced/Buzzer_PWM_advanced.ino: -------------------------------------------------------------------------------- 1 | // https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/ledc.html 2 | // https://lastminuteengineers.com/esp32-pwm-tutorial/ 3 | 4 | #define BUZZER 13 // GPIO pin connected to the buzzer 5 | #define FREQUENCY 3000 6 | #define RESOLUTION 8 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | while(!Serial); 11 | Serial.println("Setting up PWM..."); 12 | 13 | bool success = ledcAttach(BUZZER, FREQUENCY, RESOLUTION); 14 | if(success){ 15 | Serial.println("Done"); 16 | }else{ 17 | Serial.println("Error"); 18 | } 19 | delay(100); 20 | uint32_t freq = ledcReadFreq(BUZZER); 21 | Serial.println("Frequency set to " + String(freq)); 22 | } 23 | 24 | void setDuty(uint32_t duty){ 25 | bool success = ledcWrite(BUZZER, duty); 26 | if(success){ 27 | delay(50); 28 | uint32_t d = ledcRead(BUZZER); 29 | Serial.println("duty=" + String(duty) + "->" + String(d)); 30 | }else{ 31 | Serial.println("Error in ledcWrite with duty=" + String(duty)); 32 | } 33 | } 34 | 35 | void loop() { 36 | 37 | setDuty(0); // turn off LOW level 38 | delay(500); 39 | 40 | setDuty(1); 41 | delay(1000); 42 | 43 | setDuty(32); 44 | delay(1000); 45 | 46 | setDuty(64); 47 | delay(1000); 48 | 49 | 50 | setDuty(127); 51 | delay(2000); 52 | 53 | 54 | setDuty(255); // turn off HIGH level 55 | delay(1000); 56 | } 57 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/Buzzer_tone/Buzzer_tone.ino: -------------------------------------------------------------------------------- 1 | // https://docs.arduino.cc/built-in-examples/digital/toneMelody/ 2 | // https://www.hibit.dev/posts/62/playing-popular-songs-with-arduino-and-a-buzzer 3 | 4 | #include "pitches.h" 5 | #define BUZZER 13 // GPIO pin connected to the buzzer 6 | 7 | int melody[] = { 8 | NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4 9 | }; 10 | 11 | int noteDurations[] = { 12 | 4, 8, 8, 4, 4, 4, 4, 4 // 4 = q uarter note, 8 = eighth note 13 | }; 14 | 15 | 16 | void setup() { 17 | 18 | } 19 | 20 | void loop() { 21 | 22 | for (int idx = 0; idx < 8; idx++) { 23 | 24 | int noteDuration = 1000 / noteDurations[idx]; 25 | 26 | tone(BUZZER, melody[idx], noteDuration); 27 | 28 | int pauseBetweenNotes = noteDuration * 1.30; 29 | 30 | delay(pauseBetweenNotes); 31 | 32 | noTone(BUZZER); 33 | } 34 | delay(2000); 35 | } -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/FastLedWS2812Ring.md: -------------------------------------------------------------------------------- 1 | ## *NeoPixel / WS2812-16 Ring* 2 | 3 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 4 | 5 | You already have some components to use: 6 | 7 | - **WS2812-16 Ring:** 8 | 9 | This NeoPixel/WS2812-16 ring consists of 16 individually addressable RGB LEDs that can all be controlled with a single digital output of a microcontroller and chained together with other rings. 10 | 11 | ![alt text](images/ws2812-front.png) 12 | ![alt text](images/PixelRingPinout.jpg) 13 | - **[ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf)**. 14 | 15 | ![alt text](images/esp32.png) 16 | 17 | **Lets connect all together**: 18 | 19 | ![alt text](images/together.png) 20 | 21 | ## Schematic and connections 22 | 23 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 24 | 25 | - Schematic is [here](images/NeoPixelRingSchema.png). 26 | 27 | - We’ll connect WS2812-16 Ring pins with ESP32 pins using wires: 28 | - "5V" to '+5V' GPIO. 29 | - "GND" to 'GND' GPIO 30 | - "DIN" to '18' GPIO 31 | 32 | 33 | - This is how the components should be connected (please note the ESP32 board looks different than the red Olimex but the pins are the same): 34 | 35 | ![alt text](images/ModulesConnection.png) 36 | 37 | 38 | ## Code to Run (Arduino Sketches) 39 | 1. **Install the ESP32Servo library** 40 | - Go to Sketch > Include Library > Manage Libraries… 41 | - Search for FastLED. 42 | - Install the library. 43 | ![alt text](images/fastLedLib.png) 44 | 45 | 46 | 2. **Run this sketch in Arduino IDE**, compile it and and upload it. 47 | This code effectively creates a visual effect where the LEDs chase back and forth, and after every 5 cycles, all LEDs turn blue for a brief period.. 48 | 49 | ```cpp 50 | /*** 51 | 52 | The provided code is an Arduino sketch that controls a ring of NeoPixel LEDs using the FastLED library. The sketch defines the number of LEDs (NUM_LEDS) as 16 and the data pin (DATA_PIN) as 18. An array leds of type CRGB is created to hold the color values for each LED, and an integer roundCounter is initialized to 0 to keep track of the number of completed cycles. 53 | 54 | In the setup function, the FastLED.addLeds method is called to initialize the LED array with the specified type (NEOPIXEL) and data pin. This sets up the FastLED library to control the LEDs. 55 | 56 | The loop function contains the main logic for controlling the LEDs. It first lights up the LEDs sequentially from the first LED to the last, setting each LED to CRGB::LightCoral and then turning it off after a 200-millisecond delay. This creates a chasing light effect. The same process is then repeated in reverse, lighting up the LEDs from the last to the first. 57 | 58 | After completing one forward and one backward cycle, the roundCounter is incremented. If the roundCounter reaches 5, indicating that 5 complete cycles have been performed, all LEDs are set to CRGB::Blue and displayed for 1 second. The roundCounter is then reset to 0, and the process starts over. 59 | 60 | This code effectively creates a visual effect where the LEDs chase back and forth, and after every 5 cycles, all LEDs turn blue for a brief period. 61 | 62 | ***/ 63 | #include 64 | #define NUM_LEDS 16 65 | #define DATA_PIN 18 66 | CRGB leds[NUM_LEDS]; 67 | int roundCounter = 0; 68 | 69 | void setup() { 70 | FastLED.addLeds(leds, NUM_LEDS); 71 | } 72 | 73 | void loop() { 74 | // Light up LEDs from 0 to NUM_LEDS-1 75 | for (int i = 0; i < NUM_LEDS; i++) { 76 | leds[i] = CRGB::LightCoral; 77 | FastLED.show(); 78 | delay(200); 79 | leds[i] = CRGB::Black; 80 | } 81 | 82 | // Light up LEDs from NUM_LEDS-1 to 0 83 | for (int i = NUM_LEDS - 1; i >= 0; i--) { 84 | leds[i] = CRGB::LightCoral; 85 | FastLED.show(); 86 | delay(200); 87 | leds[i] = CRGB::Black; 88 | } 89 | 90 | // Increment the round counter 91 | roundCounter++; 92 | 93 | // After 5 rounds, turn all LEDs blue 94 | if (roundCounter >= 5) { 95 | for (int i = 0; i < NUM_LEDS; i++) { 96 | leds[i] = CRGB::Blue; 97 | } 98 | FastLED.show(); 99 | delay(1000); // Keep the LEDs blue for 1 second 100 | roundCounter = 0; // Reset the round counter 101 | } 102 | } 103 | 104 | ``` 105 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/NeoPixelRingWS2812.ino: -------------------------------------------------------------------------------- 1 | /*** 2 | 3 | The provided code is an Arduino sketch that controls a ring of NeoPixel LEDs using the FastLED library. The sketch defines the number of LEDs (NUM_LEDS) as 16 and the data pin (DATA_PIN) as 18. An array leds of type CRGB is created to hold the color values for each LED, and an integer roundCounter is initialized to 0 to keep track of the number of completed cycles. 4 | 5 | In the setup function, the FastLED.addLeds method is called to initialize the LED array with the specified type (NEOPIXEL) and data pin. This sets up the FastLED library to control the LEDs. 6 | 7 | The loop function contains the main logic for controlling the LEDs. It first lights up the LEDs sequentially from the first LED to the last, setting each LED to CRGB::LightCoral and then turning it off after a 200-millisecond delay. This creates a chasing light effect. The same process is then repeated in reverse, lighting up the LEDs from the last to the first. 8 | 9 | After completing one forward and one backward cycle, the roundCounter is incremented. If the roundCounter reaches 5, indicating that 5 complete cycles have been performed, all LEDs are set to CRGB::Blue and displayed for 1 second. The roundCounter is then reset to 0, and the process starts over. 10 | 11 | This code effectively creates a visual effect where the LEDs chase back and forth, and after every 5 cycles, all LEDs turn blue for a brief period. 12 | 13 | ***/ 14 | #include 15 | #define NUM_LEDS 16 16 | #define DATA_PIN 18 17 | CRGB leds[NUM_LEDS]; 18 | int roundCounter = 0; 19 | 20 | void setup() { 21 | FastLED.addLeds(leds, NUM_LEDS); 22 | } 23 | 24 | void loop() { 25 | // Light up LEDs from 0 to NUM_LEDS-1 26 | for (int i = 0; i < NUM_LEDS; i++) { 27 | leds[i] = CRGB::LightCoral; 28 | FastLED.show(); 29 | delay(200); 30 | leds[i] = CRGB::Black; 31 | } 32 | 33 | // Light up LEDs from NUM_LEDS-1 to 0 34 | for (int i = NUM_LEDS - 1; i >= 0; i--) { 35 | leds[i] = CRGB::LightCoral; 36 | FastLED.show(); 37 | delay(200); 38 | leds[i] = CRGB::Black; 39 | } 40 | 41 | // Increment the round counter 42 | roundCounter++; 43 | 44 | // After 5 rounds, turn all LEDs blue 45 | if (roundCounter >= 5) { 46 | for (int i = 0; i < NUM_LEDS; i++) { 47 | leds[i] = CRGB::Blue; 48 | } 49 | FastLED.show(); 50 | delay(1000); // Keep the LEDs blue for 1 second 51 | roundCounter = 0; // Reset the round counter 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/ModulesConnection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/ModulesConnection.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/NeoPixelRingSchema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/NeoPixelRingSchema.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/PixelRingPinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/PixelRingPinout.jpg -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/esp32.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/fastLedLib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/fastLedLib.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/together.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/together.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/FastLedNeoPixelRing/images/ws2812-front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/FastLedNeoPixelRing/images/ws2812-front.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/HappyBirthday/HappyBirthday.ino: -------------------------------------------------------------------------------- 1 | // Example from HiBit on GPIO13 2 | 3 | 4 | #include "pitches.h" 5 | 6 | #define BUZZER_PIN 13 7 | 8 | int melody[] = { 9 | NOTE_C4, NOTE_C4, 10 | NOTE_D4, NOTE_C4, NOTE_F4, 11 | NOTE_E4, NOTE_C4, NOTE_C4, 12 | NOTE_D4, NOTE_C4, NOTE_G4, 13 | NOTE_F4, NOTE_C4, NOTE_C4, 14 | 15 | NOTE_C5, NOTE_A4, NOTE_F4, 16 | NOTE_E4, NOTE_D4, NOTE_AS4, NOTE_AS4, 17 | NOTE_A4, NOTE_F4, NOTE_G4, 18 | NOTE_F4 19 | }; 20 | 21 | int durations[] = { 22 | 4, 8, 23 | 4, 4, 4, 24 | 2, 4, 8, 25 | 4, 4, 4, 26 | 2, 4, 8, 27 | 28 | 4, 4, 4, 29 | 4, 4, 4, 8, 30 | 4, 4, 4, 31 | 2 32 | }; 33 | 34 | void setup() 35 | { 36 | pinMode(BUZZER_PIN, OUTPUT); 37 | } 38 | 39 | void loop() 40 | { 41 | int size = sizeof(durations) / sizeof(int); 42 | 43 | for (int note = 0; note < size; note++) { 44 | //to calculate the note duration, take one second divided by the note type. 45 | //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. 46 | int duration = 1000 / durations[note]; 47 | tone(BUZZER_PIN, melody[note], duration); 48 | 49 | //to distinguish the notes, set a minimum time between them. 50 | //the note's duration + 30% seems to work well: 51 | int pauseBetweenNotes = duration * 1.30; 52 | delay(pauseBetweenNotes); 53 | 54 | //stop the tone playing: 55 | noTone(BUZZER_PIN); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/LiquidCrystal_PCF8574/LiquidCrystal_PCF8574.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | LiquidCrystal_PCF8574 lcd(0x27); // set the LCD address to 0x27 for a 16 chars and 2 line display 7 | 8 | 9 | void setup() { 10 | int error; 11 | 12 | Serial.begin(115200); 13 | while (!Serial); 14 | 15 | Serial.println("Probing for PCF8574 on address 0x27..."); 16 | 17 | Wire.begin(21, 22); // SDA, SCL 18 | Wire.beginTransmission(0x27); 19 | error = Wire.endTransmission(); 20 | 21 | if (error == 0) { 22 | Serial.println("LCD found."); 23 | lcd.begin(16, 2); // initialize the lcd 24 | lcd.setBacklight(1); // turn on backlight. 0 turns it off 25 | lcd.display(); // turn on the LCD, turn off with lcd.noDisplay(); 26 | lcd.clear(); // clear the display 27 | lcd.home(); // set cursor to 0,0 28 | // lcd.cursor(); // shows the current cursor position with _ 29 | lcd.noCursor(); // turn cursor off 30 | // lcd.blink(); // show a blinking cursor 31 | lcd.noBlink(); // turn off blinking cursor 32 | 33 | } else { 34 | Serial.println(": LCD not found."); 35 | Serial.print("Error: "); 36 | Serial.print(error); 37 | while(1){} 38 | } 39 | } 40 | 41 | 42 | void loop() { 43 | lcd.clear(); 44 | lcd.print("Message:"); 45 | 46 | lcd.setCursor(0, 1); 47 | lcd.print("Hi"); 48 | delay(2000); 49 | 50 | lcd.print(" there"); 51 | delay(2000); 52 | 53 | for(int i = 0; i< 10; i++){ 54 | lcd.scrollDisplayLeft(); 55 | delay(300); 56 | } 57 | 58 | lcd.blink(); 59 | lcd.setCursor(8, 1); 60 | lcd.print(" student"); 61 | 62 | delay(2000); 63 | 64 | for(int i = 0; i< 9; i++){ 65 | lcd.scrollDisplayRight(); 66 | delay(300); 67 | } 68 | lcd.noBlink(); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/old_stuff/si7021/si7021.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Si7021.h" 2 | 3 | bool enableHeater = false; 4 | uint8_t loopCnt = 0; 5 | 6 | Adafruit_Si7021 sensor = Adafruit_Si7021(); 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | Wire.begin(D5,D6); 11 | 12 | // wait for serial port to open 13 | while (!Serial) { 14 | delay(10); 15 | } 16 | 17 | Serial.println("Si7021 test!"); 18 | 19 | if (!sensor.begin()) { 20 | Serial.println("Did not find Si7021 sensor!"); 21 | while (true) 22 | ; 23 | } 24 | 25 | Serial.print("Found model "); 26 | switch(sensor.getModel()) { 27 | case SI_Engineering_Samples: 28 | Serial.print("SI engineering samples"); break; 29 | case SI_7013: 30 | Serial.print("Si7013"); break; 31 | case SI_7020: 32 | Serial.print("Si7020"); break; 33 | case SI_7021: 34 | Serial.print("Si7021"); break; 35 | case SI_UNKNOWN: 36 | default: 37 | Serial.print("Unknown"); 38 | } 39 | Serial.print(" Rev("); 40 | Serial.print(sensor.getRevision()); 41 | Serial.print(")"); 42 | Serial.print(" Serial #"); Serial.print(sensor.sernum_a, HEX); Serial.println(sensor.sernum_b, HEX); 43 | } 44 | 45 | void loop() { 46 | Serial.print("Humidity: "); 47 | Serial.print(sensor.readHumidity(), 2); 48 | Serial.print("\tTemperature: "); 49 | Serial.println(sensor.readTemperature(), 2); 50 | delay(1000); 51 | 52 | // Toggle heater enabled state every 30 seconds 53 | // An ~1.8 degC temperature increase can be noted when heater is enabled 54 | if (++loopCnt == 30) { 55 | enableHeater = !enableHeater; 56 | sensor.heater(enableHeater); 57 | Serial.print("Heater Enabled State: "); 58 | if (sensor.isHeaterEnabled()) 59 | Serial.println("ENABLED"); 60 | else 61 | Serial.println("DISABLED"); 62 | 63 | loopCnt = 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/esp32.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/library_esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/library_esp32.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/olimex_esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/olimex_esp32.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/servo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/servo.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/servo_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/servo_schematic.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/together.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/together.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/images/wires_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/servo/images/wires_connections.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/servo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The provided code is an Arduino sketch that demonstrates how to control a servo motor using the ESP32Servo library. The sketch begins by defining a constant `servoPin` with a value of 13, which represents the GPIO pin on the ESP32 to which the servo motor is connected. An instance of the Servo class, named `servo1`, is then created to control the servo motor. 3 | 4 | In the `setup` function, the serial communication is initialized with a baud rate of 115200 using `Serial.begin(115200)`. This allows for communication between the ESP32 and a connected computer, which can be useful for debugging or monitoring the servo motor's behavior. The servo motor is then attached to the specified pin (servoPin) using the `attach` method of the Servo class. 5 | 6 | The `loop` function contains the main logic for controlling the servo motor. It consists of two for-loops that move the servo motor back and forth between 0 and 180 degrees. The first for-loop increments the servo position from 0 to 180 degrees in steps of 1 degree. For each position, the `write` method of the Servo class is called to set the servo to the specified angle, and the current position is printed to the serial monitor using `Serial.println(posDegrees)`. A delay of 20 milliseconds is added between each step to control the speed of the servo movement. 7 | 8 | The second for-loop decrements the servo position from 180 to 0 degrees, following the same process as the first loop. This back-and-forth movement of the servo motor continues indefinitely, causing the servo to sweep smoothly between the two positions. 9 | */ 10 | 11 | #include 12 | 13 | static const int servoPin = 13; 14 | 15 | Servo servo1; 16 | 17 | void setup() { 18 | 19 | Serial.begin(115200); 20 | servo1.attach(servoPin); 21 | } 22 | 23 | void loop() { 24 | for(int posDegrees = 0; posDegrees <= 180; posDegrees++) { 25 | servo1.write(posDegrees); 26 | Serial.println(posDegrees); 27 | delay(20); 28 | } 29 | 30 | for(int posDegrees = 180; posDegrees >= 0; posDegrees--) { 31 | servo1.write(posDegrees); 32 | Serial.println(posDegrees); 33 | delay(20); 34 | } 35 | } -------------------------------------------------------------------------------- /04-displays-and-actuators/src/servo/servo.md: -------------------------------------------------------------------------------- 1 | ## *Stepper motor* 2 | 3 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 4 | 5 | You already have some components to use: 6 | 7 | - **Servo Futaba S3003 :** 8 | 9 | A servomotor is a rotary or linear actuator that allows for precise control of angular or linear position, velocity, and acceleration in a mechanical system. 10 | 11 | ![alt text](images/servo.png) 12 | 13 | - **[ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf)**. 14 | 15 | ![alt text](images/esp32.png) 16 | 17 | **Lets connect all together**: 18 | 19 | ![alt text](images/together.png) 20 | 21 | ## Schematic and connections 22 | 23 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 24 | 25 | - Schematic is [here](images/servo_schematic.png). 26 | 27 | - We’ll connect servo wires: 28 | - "RED" to '+5V' GPIO. 29 | - "BROWN" to 'GND' GPIO 30 | - "Yellow" to '13' GPIO 31 | 32 | 33 | - This is how the components should be connected (please note the ESP32 board looks different than the red Olimex but the pins are the same): 34 | 35 | ![alt text](images/wires_connections.png) 36 | 37 | 38 | ## Code to Run (Arduino Sketches) 39 | 1. **Install the ESP32Servo library** 40 | - Go to Sketch > Include Library > Manage Libraries… 41 | - Search for ESP32Servo. 42 | - Install the library. 43 | ![alt text](images/library_esp32.png) 44 | 45 | 46 | 2. **Run this sketch in Arduino IDE**, compile it and and upload it to the board. 47 | The servo position will change from 180 to 0 degrees and then 0 to 180 degrees. This back-and-forth movement of the servo motor continues indefinitely, causing the servo to sweep smoothly between the two positions. 48 | 49 | ```cpp 50 | /* 51 | The provided code is an Arduino sketch that demonstrates how to control a servo motor using the ESP32Servo library. The sketch begins by defining a constant `servoPin` with a value of 13, which represents the GPIO pin on the ESP32 to which the servo motor is connected. An instance of the Servo class, named `servo1`, is then created to control the servo motor. 52 | 53 | In the `setup` function, the serial communication is initialized with a baud rate of 115200 using `Serial.begin(115200)`. This allows for communication between the ESP32 and a connected computer, which can be useful for debugging or monitoring the servo motor's behavior. The servo motor is then attached to the specified pin (servoPin) using the `attach` method of the Servo class. 54 | 55 | The `loop` function contains the main logic for controlling the servo motor. It consists of two for-loops that move the servo motor back and forth between 0 and 180 degrees. The first for-loop increments the servo position from 0 to 180 degrees in steps of 1 degree. For each position, the `write` method of the Servo class is called to set the servo to the specified angle, and the current position is printed to the serial monitor using `Serial.println(posDegrees)`. A delay of 20 milliseconds is added between each step to control the speed of the servo movement. 56 | 57 | The second for-loop decrements the servo position from 180 to 0 degrees, following the same process as the first loop. This back-and-forth movement of the servo motor continues indefinitely, causing the servo to sweep smoothly between the two positions. 58 | */ 59 | 60 | #include 61 | 62 | static const int servoPin = 13; 63 | 64 | Servo servo1; 65 | 66 | void setup() { 67 | 68 | Serial.begin(115200); 69 | servo1.attach(servoPin); 70 | } 71 | 72 | void loop() { 73 | for(int posDegrees = 0; posDegrees <= 180; posDegrees++) { 74 | servo1.write(posDegrees); 75 | Serial.println(posDegrees); 76 | delay(20); 77 | } 78 | 79 | for(int posDegrees = 180; posDegrees >= 0; posDegrees--) { 80 | servo1.write(posDegrees); 81 | Serial.println(posDegrees); 82 | delay(20); 83 | } 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/ULN2003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/ULN2003.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/ULN2003_pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/ULN2003_pinout.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/olimex_esp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/olimex_esp32.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/sample.jpg -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/schematic_stepper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/schematic_stepper.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/stepper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/stepper.jpg -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/stepper_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/stepper_1.jpg -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/images/stepper_motor_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/04-displays-and-actuators/src/stepper_motor/images/stepper_motor_schem.png -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/stepper_motor.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The provided code is an Arduino sketch that demonstrates how to control a stepper motor using the Stepper library. The sketch begins by including the Stepper library with `#include `, which provides the necessary functions to control the stepper motor. 3 | 4 | A constant `stepsPerRevolution` is defined with a value of 1024, representing the number of steps the motor needs to complete one full revolution. This value can be adjusted to match the specifications of the stepper motor being used. 5 | 6 | The ULN2003 motor driver pins are defined using `#define` directives. These pins (IN1, IN2, IN3, and IN4) are connected to the Arduino and control the stepper motor. The specific pin numbers (19, 18, 5, and 17) correspond to the digital pins on the Arduino board. 7 | 8 | An instance of the Stepper class, named `myStepper`, is created and initialized with the number of steps per revolution and the pin numbers. This instance will be used to control the stepper motor. 9 | 10 | In the `setup` function, the speed of the stepper motor is set to 5 revolutions per minute (rpm) using the `setSpeed` method. Additionally, the serial port is initialized with a baud rate of 115200 using `Serial.begin(115200)`. This allows for communication between the Arduino and a connected computer, which can be useful for debugging or monitoring the motor's behavior. 11 | 12 | The `loop` function contains the main logic for controlling the stepper motor. It first prints "Going clockwise" to the serial monitor and then commands the motor to step one full revolution in the clockwise direction using `myStepper.step(stepsPerRevolution)`. After a delay of 1000 milliseconds (1 second), it prints "Going counterclockwise" to the serial monitor and commands the motor to step one full revolution in the counterclockwise direction using `myStepper.step(-stepsPerRevolution)`. This loop repeats indefinitely, causing the motor to alternate between clockwise and counterclockwise rotations. 13 | */ 14 | #include 15 | 16 | const int stepsPerRevolution = 1024; // change this to fit the number of steps per revolution 17 | 18 | // ULN2003 Motor Driver Pins 19 | #define IN1 19 20 | #define IN2 18 21 | #define IN3 5 22 | #define IN4 17 23 | 24 | // initialize the stepper library 25 | Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4); 26 | 27 | void setup() { 28 | // set the speed at 5 rpm 29 | myStepper.setSpeed(5); 30 | // initialize the serial port 31 | Serial.begin(115200); 32 | } 33 | 34 | void loop() { 35 | // step one revolution in one direction: 36 | Serial.println("Going clockwise"); 37 | myStepper.step(stepsPerRevolution); 38 | delay(1000); 39 | 40 | // step one revolution in the other direction: 41 | Serial.println("Going counterclockwise"); 42 | myStepper.step(-stepsPerRevolution); 43 | delay(1000); 44 | } -------------------------------------------------------------------------------- /04-displays-and-actuators/src/stepper_motor/stepper_motor.md: -------------------------------------------------------------------------------- 1 | ## *Stepper motor* 2 | 3 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 4 | 5 | You already have some components to use: 6 | 7 | - **stepper motor 28BYJ-48:** 8 | 9 | A stepper motor is a brushless DC electric motor that divides a full rotation into a number of steps. It moves one step at a time, and each step is the same size 10 | 11 | ![alt text](images/stepper.jpg) ![alt text](images/stepper_1.jpg) 12 | 13 | **ULN2003 Motor Driver**. 14 | To interface the stepper motor with the ESP32, we’ll use the ULN2003 motor driver, as shown in the figure below. 15 | ![alt text](images/ULN2003.png)![alt text](images/ULN2003_pinout.png) 16 | 17 | **Lets connect all together**: 18 | 19 | ![alt text](images/sample.jpg) 20 | 21 | ## Schematic and connections 22 | 23 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 24 | 25 | - Schematic is [here](images/schematic_stepper.png). 26 | 27 | - We’ll connect IN1, IN2, IN3, and IN4 to GPIOs 19, 18, 5, and 17. You can use any other suitable digital pins 28 | 29 | - ULN2003 driver '+' pin is connected to ESP32 '+5V' pin. The '-' pin to the ESP32 'GND' pin. 30 | 31 | - This is how the components should be connected (please note the ESP32 board looks different than the red Olimex but the pins are the same): 32 | 33 | ![alt text](images/stepper_motor_schem.png) 34 | 35 | 36 | ## Code to Run (Arduino Sketches) 37 | 38 | 1. Run this sketch in Arduino IDE, compile it and and upload it to the board. The stepper will start to rotate slowly to make 1024 steps per revolution with 5 revolutions per minite. 39 | 40 | ```cpp 41 | /* 42 | The provided code is an Arduino sketch that demonstrates how to control a stepper motor using the Stepper library. The sketch begins by including the Stepper library with `#include `, which provides the necessary functions to control the stepper motor. 43 | 44 | A constant `stepsPerRevolution` is defined with a value of 1024, representing the number of steps the motor needs to complete one full revolution. This value can be adjusted to match the specifications of the stepper motor being used. 45 | 46 | The ULN2003 motor driver pins are defined using `#define` directives. These pins (IN1, IN2, IN3, and IN4) are connected to the Arduino and control the stepper motor. The specific pin numbers (19, 18, 5, and 17) correspond to the digital pins on the Arduino board. 47 | 48 | An instance of the Stepper class, named `myStepper`, is created and initialized with the number of steps per revolution and the pin numbers. This instance will be used to control the stepper motor. 49 | 50 | In the `setup` function, the speed of the stepper motor is set to 5 revolutions per minute (rpm) using the `setSpeed` method. Additionally, the serial port is initialized with a baud rate of 115200 using `Serial.begin(115200)`. This allows for communication between the Arduino and a connected computer, which can be useful for debugging or monitoring the motor's behavior. 51 | 52 | The `loop` function contains the main logic for controlling the stepper motor. It first prints "Going clockwise" to the serial monitor and then commands the motor to step one full revolution in the clockwise direction using `myStepper.step(stepsPerRevolution)`. After a delay of 1000 milliseconds (1 second), it prints "Going counterclockwise" to the serial monitor and commands the motor to step one full revolution in the counterclockwise direction using `myStepper.step(-stepsPerRevolution)`. This loop repeats indefinitely, causing the motor to alternate between clockwise and counterclockwise rotations. 53 | */ 54 | #include 55 | 56 | const int stepsPerRevolution = 1024; // change this to fit the number of steps per revolution 57 | 58 | // ULN2003 Motor Driver Pins 59 | #define IN1 19 60 | #define IN2 18 61 | #define IN3 5 62 | #define IN4 17 63 | 64 | // initialize the stepper library 65 | Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4); 66 | 67 | void setup() { 68 | // set the speed at 5 rpm 69 | myStepper.setSpeed(5); 70 | // initialize the serial port 71 | Serial.begin(115200); 72 | } 73 | 74 | void loop() { 75 | // step one revolution in one direction: 76 | Serial.println("Going clockwise"); 77 | myStepper.step(stepsPerRevolution); 78 | delay(1000); 79 | 80 | // step one revolution in the other direction: 81 | Serial.println("Going counterclockwise"); 82 | myStepper.step(-stepsPerRevolution); 83 | delay(1000); 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /05-sensors-displays-exercise/CM1106_I2C/CM1106_I2C.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | CM1106_I2C cm1106_i2c; 4 | 5 | // #define CM1107 6 | 7 | void setup() { 8 | Serial.begin(115200); 9 | while(!Serial); 10 | 11 | Wire.begin(21, 22); // SDA, SCL 12 | 13 | cm1106_i2c.begin(); 14 | 15 | delay(1000); 16 | cm1106_i2c.read_serial_number(); 17 | delay(1000); 18 | cm1106_i2c.check_sw_version(); 19 | delay(1000); 20 | } 21 | 22 | void loop() { 23 | uint8_t ret = cm1106_i2c.measure_result(); 24 | 25 | if (ret == 0) { 26 | Serial.print("Co2 : "); 27 | Serial.println(cm1106_i2c.co2); 28 | Serial.println("Status >>"); 29 | 30 | 31 | #if defined(CM1107) 32 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_PREHEATING)) { 33 | Serial.println("Preheating"); 34 | } else { 35 | Serial.println("Preheat complete"); 36 | } 37 | 38 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_OPERATING_NORMAL)) { 39 | Serial.println("Sensor Error"); 40 | } else { 41 | Serial.println("Operating normal"); 42 | } 43 | 44 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_OVER_MEASUREMENT_RANGE)) { 45 | Serial.println("Over Measurement Range"); 46 | } else { 47 | Serial.println("Normal Measurement Range"); 48 | } 49 | 50 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_LESS_THAN_MEASUREMENT_RANGE)) { 51 | Serial.println("Less than Measurement Range"); 52 | } else { 53 | Serial.println("Normal Measurement Range"); 54 | } 55 | 56 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_CALIBRATED)) { 57 | Serial.println("Non-calibrated"); 58 | } else { 59 | Serial.println("Calibrated"); 60 | } 61 | 62 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_LIGHT_AGING)) { 63 | Serial.println("Light Aging"); 64 | } else { 65 | Serial.println("Light Normal"); 66 | } 67 | 68 | if (cm1106_i2c.status & (1 << CM1106_I2C_STATUS_CM1107_DRIFT)) { 69 | Serial.println("Drift"); 70 | } else { 71 | Serial.println("Non-Drift"); 72 | } 73 | 74 | 75 | #else 76 | switch (cm1106_i2c.status) { 77 | case CM1106_I2C_STATUS_PREHEATING: { 78 | Serial.println("Preheating"); 79 | break; 80 | } 81 | case CM1106_I2C_STATUS_NORMAL_OPERATION: { 82 | Serial.println("Normal operation"); 83 | break; 84 | } 85 | case CM1106_I2C_STATUS_OPERATING_TROUBLE: { 86 | Serial.println("Operating trouble"); 87 | break; 88 | } 89 | case CM1106_I2C_STATUS_OUT_OF_FS: { 90 | Serial.println("Out of FS"); 91 | break; 92 | } 93 | case CM1106_I2C_STATUS_NON_CALIBRATED: { 94 | Serial.println("Non calibrated"); 95 | break; 96 | } 97 | } 98 | #endif 99 | 100 | 101 | 102 | 103 | } 104 | delay(1000); 105 | } -------------------------------------------------------------------------------- /05-sensors-displays-exercise/Exercises.md: -------------------------------------------------------------------------------- 1 | # Monochrome OLED 2 | Your task is to become familiar with the [SSD1306 display](https://learn.adafruit.com/monochrome-oled-breakouts), to run the example and to modify it to print your name. 3 | 4 | # Accelerometer / Gyro 5 | Become familiar with [GY-521 / MPU6050 accelerometer gyro](https://randomnerdtutorials.com/esp32-mpu-6050-accelerometer-gyroscope-arduino/). Run the example and modify the range and filter frequency. 6 | 7 | 8 | # VoC sensors 9 | ## MQ2 10 | Read [this article](https://diyi0t.com/mq2-gas-sensor-arduino-esp8266-esp32/) to become familiar with the principle of operation of the MQ sensor family. Run the `MQ2` exercise and try to convert the analog reading to ppm, according to the documentation. 11 | 12 | ## SGP40 13 | This is a more advanced sensor. Read this [excellent Adafruit article](https://learn.adafruit.com/adafruit-sgp40/arduino) for more details. This sensor is intended for indoor air quality monitoring and is therefore quite slow (minutes). There is also an initial warm up period (aka learning phase) around 1 minute. 14 | 15 | More information about the sensor can be found on the manufacturer's page: https://sensirion.com/products/catalog/SGP40. 16 | 17 | [The datasheet, page 4](https://sensirion.com/media/documents/296373BB/6203C5DF/Sensirion_Gas_Sensors_Datasheet_SGP40.pdf) gives the sensitivity curve for different VOCs. 18 | 19 | # Dust sensor -------------------------------------------------------------------------------- /05-sensors-displays-exercise/GY_521/GY_521.ino: -------------------------------------------------------------------------------- 1 | // Basic demo for accelerometer readings from Adafruit MPU6050 2 | // Adapted to ESP32 I2C pins 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | Adafruit_MPU6050 mpu; 9 | 10 | void setup(void) { 11 | Serial.begin(115200); 12 | while (!Serial) 13 | delay(10); // will pause Zero, Leonardo, etc until serial console opens 14 | 15 | Serial.println("Adafruit MPU6050 test!"); 16 | 17 | Wire.begin(21, 22); // SDA, SCL 18 | 19 | // Try to initialize! 20 | if (!mpu.begin()) { 21 | Serial.println("Failed to find MPU6050 chip"); 22 | while (1) { 23 | delay(10); 24 | } 25 | } 26 | Serial.println("MPU6050 Found!"); 27 | 28 | mpu.setAccelerometerRange(MPU6050_RANGE_8_G); 29 | Serial.print("Accelerometer range set to: "); 30 | switch (mpu.getAccelerometerRange()) { 31 | case MPU6050_RANGE_2_G: 32 | Serial.println("+-2G"); 33 | break; 34 | case MPU6050_RANGE_4_G: 35 | Serial.println("+-4G"); 36 | break; 37 | case MPU6050_RANGE_8_G: 38 | Serial.println("+-8G"); 39 | break; 40 | case MPU6050_RANGE_16_G: 41 | Serial.println("+-16G"); 42 | break; 43 | } 44 | mpu.setGyroRange(MPU6050_RANGE_500_DEG); 45 | Serial.print("Gyro range set to: "); 46 | switch (mpu.getGyroRange()) { 47 | case MPU6050_RANGE_250_DEG: 48 | Serial.println("+- 250 deg/s"); 49 | break; 50 | case MPU6050_RANGE_500_DEG: 51 | Serial.println("+- 500 deg/s"); 52 | break; 53 | case MPU6050_RANGE_1000_DEG: 54 | Serial.println("+- 1000 deg/s"); 55 | break; 56 | case MPU6050_RANGE_2000_DEG: 57 | Serial.println("+- 2000 deg/s"); 58 | break; 59 | } 60 | 61 | mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); 62 | Serial.print("Filter bandwidth set to: "); 63 | switch (mpu.getFilterBandwidth()) { 64 | case MPU6050_BAND_260_HZ: 65 | Serial.println("260 Hz"); 66 | break; 67 | case MPU6050_BAND_184_HZ: 68 | Serial.println("184 Hz"); 69 | break; 70 | case MPU6050_BAND_94_HZ: 71 | Serial.println("94 Hz"); 72 | break; 73 | case MPU6050_BAND_44_HZ: 74 | Serial.println("44 Hz"); 75 | break; 76 | case MPU6050_BAND_21_HZ: 77 | Serial.println("21 Hz"); 78 | break; 79 | case MPU6050_BAND_10_HZ: 80 | Serial.println("10 Hz"); 81 | break; 82 | case MPU6050_BAND_5_HZ: 83 | Serial.println("5 Hz"); 84 | break; 85 | } 86 | 87 | Serial.println(""); 88 | delay(100); 89 | } 90 | 91 | void loop() { 92 | 93 | /* Get new sensor events with the readings */ 94 | sensors_event_t a, g, temp; 95 | mpu.getEvent(&a, &g, &temp); 96 | 97 | /* Print out the values */ 98 | Serial.print("Acceleration X: "); 99 | Serial.print(a.acceleration.x); 100 | Serial.print(", Y: "); 101 | Serial.print(a.acceleration.y); 102 | Serial.print(", Z: "); 103 | Serial.print(a.acceleration.z); 104 | Serial.println(" m/s^2"); 105 | 106 | Serial.print("Rotation X: "); 107 | Serial.print(g.gyro.x); 108 | Serial.print(", Y: "); 109 | Serial.print(g.gyro.y); 110 | Serial.print(", Z: "); 111 | Serial.print(g.gyro.z); 112 | Serial.println(" rad/s"); 113 | 114 | Serial.print("Temperature: "); 115 | Serial.print(temp.temperature); 116 | Serial.println(" degC"); 117 | 118 | Serial.println(""); 119 | delay(500); 120 | } -------------------------------------------------------------------------------- /05-sensors-displays-exercise/MQ2/MQ2.ino: -------------------------------------------------------------------------------- 1 | #define SENSOR 25 2 | 3 | void setup() { 4 | Serial.begin(115200); 5 | while (!Serial); 6 | 7 | pinMode(SENSOR, INPUT); 8 | Serial.println("MQ2 sensor"); 9 | } 10 | 11 | 12 | void loop(){ 13 | 14 | Serial.print("Analog output: "); 15 | Serial.println(analogRead(SENSOR)); 16 | delay(100); 17 | } 18 | -------------------------------------------------------------------------------- /05-sensors-displays-exercise/SGP40/SGP40.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_SGP40.h" 2 | #include "SHT2x.h" 3 | 4 | Adafruit_SGP40 sgp; // default address 0x59 5 | SHT2x sht; // default address 0x40 6 | 7 | void setup() { 8 | Serial.begin(115200); 9 | while (!Serial); 10 | 11 | Serial.println("SGP40 example with temperature compensation"); 12 | Wire.begin(21, 22); // SDA, SCL 13 | 14 | if (! sgp.begin()){ 15 | Serial.println("ERROR: SGP40 sensor not found"); 16 | while (1); 17 | } 18 | 19 | if (!sht.begin()) { 20 | Serial.println("ERROR: SHT sensor not found"); 21 | while (1); 22 | } 23 | 24 | Serial.print("Found all sensors. SGP serial: "); 25 | Serial.print(sgp.serialnumber[0], HEX); 26 | Serial.print(sgp.serialnumber[1], HEX); 27 | Serial.println(sgp.serialnumber[2], HEX); 28 | delay(3000); 29 | } 30 | 31 | void loop() { 32 | uint16_t sraw; 33 | int32_t voc_index; 34 | 35 | sht.read(); 36 | float t = sht.getTemperature(); 37 | float h = sht.getHumidity(); 38 | Serial.print(t); Serial.print(" C"); Serial.print("\t"); Serial.print(h); Serial.println("\%"); 39 | 40 | sraw = sgp.measureRaw(t, h); 41 | Serial.print("Raw measurement: "); Serial.println(sraw); 42 | 43 | voc_index = sgp.measureVocIndex(t, h); 44 | Serial.print("Voc Index: "); Serial.println(voc_index); 45 | 46 | delay(2000); 47 | } 48 | -------------------------------------------------------------------------------- /06-connectivity-1/Connectivity1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/06-connectivity-1/Connectivity1.pdf -------------------------------------------------------------------------------- /06-connectivity-1/Exercises.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | ## ESP-NOW 4 | Make a transmitter and receiver with two ESP devices (or only sender, we will provide few receivers for shared usage). 5 | 6 | ### Prepare transmitter ESP 7 | > [!NOTE] 8 | > You can skip MAC address step 1 if using already prepared receiver. 9 | 10 | 1. First you need to obtain WIFI MAC address of the receiver device. [Run this sketch](src/ESP-Now/mac-scanner.ino) on the receiver ESP and obtain MAC address from the serial console. 11 | 12 | 2. [Upload this sketch](src/ESP-Now/espnow-transmitter.ino) on the transmitter ESP and do not forget to change the MAC address in the code. Now when you power on the transmitter it will start to transmit messages each 1 sec and will print results in the serial console. 13 | 14 | ### Prepare the receiver ESP 15 | [Upload this sketch](src/ESP-Now/espnow-receiver.ino) on the receiver ESP device and run it. On the serial console it will print what it receives. Also a single ESP device can receive ESP-Now data from multiple receivers, as long as they are configured with it's MAC Address. 16 | 17 | (Optional) You can extend the exercise by modifying sending data by receiving input from a button or connecting display on the receiver to show the data. Or modify the sketch to turn on the builtin LED on the receiver (https://circuits4you.com/2018/02/02/esp32-led-blink-example/) by pressing the BOOT button on the transmitter (BOOT button is connected to GPIO0). 18 | 19 | - more about ESP-NOW: https://docs.arduino.cc/tutorials/nano-esp32/esp-now/ 20 | - Exercise is based on this tutorial: https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/ 21 | 22 | ## Bluetooth Low Energy 23 | Use ESP32 to [emulate a heart rate monitor](src/02_BLE_heartrate/02_BLE_heartrate.ino). 24 | 25 | * Use the [SelfLoops HRV application (Android)](https://play.google.com/store/apps/details?id=com.wellness.selfloops.hrv&hl=en_US&gl=US) to test if it works. 26 | 27 | ## UART 28 | Review the code of the [RS485 Modbus smart meter example](https://embeddedthere.com/how-to-interface-esp32-with-rs485-modbus-sensors-with-example-code/). 29 | 30 | > ESP32 has [three hardware UART devices](https://circuits4you.com/2018/12/31/esp32-hardware-serial2-example/) of which at least one is available, so you don't need [software serial as in ESP8266](https://github.com/plerup/espsoftwareserial). 31 | > - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html 32 | 33 | ## SPI 34 | Review the code of the [official SPI example](https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino). 35 | 36 | > ESP32 has [four hardware SPI devices](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html), of which only two can be used by your program (HSPI and VSPI). 37 | > - [More details about the SPI protocol](https://www.analog.com/en/analog-dialogue/articles/introduction-to-spi-interface.html#) 38 | 39 | ## OneWire 40 | Connect the DS18b20 temp sensor to the board and [measure its temperature](src/DS18x20_multiple/DS18x20_multiple.ino) 41 | 42 | You can connect the sensor in two ways: 43 | - Three wire interface: https://randomnerdtutorials.com/guide-for-ds18b20-temperature-sensor-with-arduino/ 44 | - Parasitic power: https://forum.arduino.cc/t/ds18b20-problem-with-parasite-power-mode/415950 45 | 46 | ![schematic](https://europe1.discourse-cdn.com/arduino/original/4X/b/9/a/b9a8e50187caa34614fcf361a51fd5f0f04bf393.jpeg "Parasitic power") 47 | 48 | ## (Optional) LoRa 49 | Review the implementation of the LoRa client device. 50 | 51 | -------------------------------------------------------------------------------- /06-connectivity-1/board_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/06-connectivity-1/board_name.png -------------------------------------------------------------------------------- /06-connectivity-1/src/01_OneWire/README.md: -------------------------------------------------------------------------------- 1 | # Try to adapt these instructions to ESP8266 2 | 3 | https://create.arduino.cc/projecthub/iotboys/how-to-use-ds18b20-water-proof-temperature-sensor-2adecc -------------------------------------------------------------------------------- /06-connectivity-1/src/02_BLE_heartrate/02_BLE_heartrate.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Original example by: https://github.com/SensorsIot/Bluetooth-BLE-on-Arduino-IDE/blob/master/Polar_H7_Sensor/Polar_H7_Sensor.ino 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | byte flags = 0b00111110; 12 | byte bpm = 1; 13 | byte heart[8] = { 0b00001110, 60, 0, 0, 0 , 0, 0, 0}; 14 | byte hrmPos[1] = {2}; 15 | 16 | #define heartRateService BLEUUID((uint16_t)0x180D) 17 | 18 | BLECharacteristic heartRateMeasurementCharacteristics(BLEUUID((uint16_t)0x2A37), BLECharacteristic::PROPERTY_NOTIFY); 19 | BLECharacteristic sensorPositionCharacteristic(BLEUUID((uint16_t)0x2A38), BLECharacteristic::PROPERTY_READ); 20 | 21 | void setup() { 22 | 23 | Serial.begin(115200); 24 | Serial.println("Start"); 25 | 26 | BLEDevice::init("Pavel H7"); 27 | BLEServer *pServer = BLEDevice::createServer(); 28 | BLEService *pService = pServer->createService(heartRateService); 29 | 30 | pService->addCharacteristic(&heartRateMeasurementCharacteristics); 31 | pService->addCharacteristic(&sensorPositionCharacteristic); 32 | 33 | BLEDescriptor heartRateDescriptor(BLEUUID((uint16_t)0x2901)); 34 | heartRateDescriptor.setValue("Rate from 0 to 200"); 35 | heartRateMeasurementCharacteristics.addDescriptor(&heartRateDescriptor); 36 | heartRateMeasurementCharacteristics.addDescriptor(new BLE2902()); 37 | 38 | BLEDescriptor sensorPositionDescriptor(BLEUUID((uint16_t)0x2901)); 39 | sensorPositionDescriptor.setValue("Position 0 - 6"); 40 | sensorPositionCharacteristic.addDescriptor(&sensorPositionDescriptor); 41 | 42 | 43 | pServer->getAdvertising()->addServiceUUID(heartRateService); 44 | 45 | pService->start(); 46 | pServer->getAdvertising()->start(); 47 | } 48 | 49 | void loop() { 50 | 51 | heart[1] = (byte)bpm; 52 | int energyUsed = 3000; 53 | heart[3] = energyUsed / 256; 54 | heart[2] = energyUsed - (heart[2] * 256); 55 | Serial.println("BPM:" + String(bpm)); 56 | 57 | heartRateMeasurementCharacteristics.setValue(heart, 8); 58 | heartRateMeasurementCharacteristics.notify(); 59 | 60 | sensorPositionCharacteristic.setValue(hrmPos, 1); 61 | bpm++; 62 | 63 | delay(2000); 64 | } 65 | -------------------------------------------------------------------------------- /06-connectivity-1/src/04_LoraModuleClient/04_LoraModuleClient.ino: -------------------------------------------------------------------------------- 1 | // A modified exampleof https://github.com/matthijskooijman/arduino-lmic 2 | 3 | #include 4 | #include 5 | 6 | // TTN supplied credentials 7 | static const PROGMEM u1_t NWKSKEY[16] = { 0x1C, 0x6D, 0x4B, 0x07, 0x2A, 0x99, 0x36, 0x11, 0x61, 0x22, 0xF2, 0x50, 0xA8, 0xDF, 0x99, 0x29 }; 8 | static const PROGMEM u1_t APPSKEY[16] = { 0x8C, 0x14, 0x7A, 0x5D, 0xA6, 0x9D, 0x89, 0xC3, 0x01, 0xF3, 0xE0, 0x7C, 0xE8, 0x3D, 0xDD, 0xE5 }; 9 | static const u4_t DEVADDR = 0x26011E17; 10 | 11 | // Void callbacks 12 | void os_getArtEui (u1_t* buf) { } 13 | void os_getDevEui (u1_t* buf) { } 14 | void os_getDevKey (u1_t* buf) { } 15 | 16 | 17 | //static uint8_t mydata[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}; 18 | static uint8_t mydata[] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}; 19 | static osjob_t sendjob; 20 | 21 | const lmic_pinmap lmic_pins = { 22 | .nss = 8, // Digital pin connected to SS 23 | .rxtx = LMIC_UNUSED_PIN, // we do not use these 24 | .rst = 4, // Digital pin connected to RST 25 | .dio = {7, 1, 2}, // Digital pin connected to 00,01,02 26 | }; 27 | 28 | void onEvent (ev_t ev) { 29 | 30 | switch(ev) { 31 | case EV_SCAN_TIMEOUT: 32 | Serial.println(F("EV_SCAN_TIMEOUT")); 33 | break; 34 | case EV_BEACON_FOUND: 35 | Serial.println(F("EV_BEACON_FOUND")); 36 | break; 37 | case EV_BEACON_MISSED: 38 | Serial.println(F("EV_BEACON_MISSED")); 39 | break; 40 | case EV_BEACON_TRACKED: 41 | Serial.println(F("EV_BEACON_TRACKED")); 42 | break; 43 | case EV_JOINING: 44 | Serial.println(F("EV_JOINING")); 45 | break; 46 | case EV_JOINED: 47 | Serial.println(F("EV_JOINED")); 48 | break; 49 | case EV_RFU1: 50 | Serial.println(F("EV_RFU1")); 51 | break; 52 | case EV_JOIN_FAILED: 53 | Serial.println(F("EV_JOIN_FAILED")); 54 | break; 55 | case EV_REJOIN_FAILED: 56 | Serial.println(F("EV_REJOIN_FAILED")); 57 | break; 58 | break; 59 | case EV_TXCOMPLETE: 60 | Serial.println(F("EV_TXCOMPLETE")); 61 | if (LMIC.txrxFlags & TXRX_ACK) 62 | Serial.println(F("Received ack")); 63 | if(LMIC.dataLen) { 64 | // data received in rx slot after tx 65 | Serial.print(F("Data Received: ")); 66 | Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen); 67 | Serial.println(); 68 | } 69 | delay(10000); 70 | do_send(&sendjob); // data must be prepared in the loop function 71 | break; 72 | case EV_LOST_TSYNC: 73 | Serial.println(F("EV_LOST_TSYNC")); 74 | break; 75 | case EV_RESET: 76 | Serial.println(F("EV_RESET")); 77 | break; 78 | case EV_RXCOMPLETE: 79 | // data received in ping slot 80 | Serial.println(F("EV_RXCOMPLETE")); 81 | break; 82 | case EV_LINK_DEAD: 83 | Serial.println(F("EV_LINK_DEAD")); 84 | break; 85 | case EV_LINK_ALIVE: 86 | Serial.println(F("EV_LINK_ALIVE")); 87 | break; 88 | default: 89 | Serial.println(F("Unknown event")); 90 | break; 91 | } 92 | } 93 | 94 | void do_send(osjob_t* j){ 95 | 96 | if (LMIC.opmode & OP_TXRXPEND) { 97 | Serial.println(F("OP_TXRXPEND not ready!")); 98 | } else { 99 | LMIC_setTxData2(1, mydata, sizeof(mydata), 0); 100 | Serial.println(F("Packet queued")); 101 | } 102 | } 103 | 104 | void setup() { 105 | delay(3000); 106 | Serial.begin(9600); 107 | Serial.println(F("Starting")); 108 | 109 | os_init(); 110 | LMIC_reset(); 111 | #ifdef PROGMEM 112 | uint8_t appskey[sizeof(APPSKEY)]; 113 | uint8_t nwkskey[sizeof(NWKSKEY)]; 114 | memcpy_P(appskey, APPSKEY, sizeof(APPSKEY)); 115 | memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY)); 116 | LMIC_setSession (0x1, DEVADDR, nwkskey, appskey); 117 | #else 118 | LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); 119 | #endif 120 | LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 121 | LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band 122 | LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 123 | LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 124 | LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 125 | LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 126 | LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 127 | LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 128 | LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band 129 | LMIC_setLinkCheckMode(0); 130 | LMIC_setDrTxpow(DR_SF7, 14); // SF7 and max power from module = 14 131 | LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); 132 | LMIC.dn2Dr = DR_SF9; 133 | do_send(&sendjob); 134 | } 135 | 136 | void loop() { 137 | 138 | os_runloop_once(); //LoRa statemachine 139 | 140 | // here you are supposed to read sensors and update your data 141 | //uint8_t tmp = mydata[0]; 142 | //mydata[0]= mydata[1]; 143 | //mydata[1]= tmp; 144 | } 145 | -------------------------------------------------------------------------------- /06-connectivity-1/src/BLE_server/BLE_server.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define ALERT_NOTIFICATION_SERVICE_UUID "1811" // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.alert_notification.xml 8 | 9 | 10 | BLECharacteristic *pNewAlertCharacteristic; 11 | BLEServer *pServer; 12 | 13 | void setup() { 14 | Serial.begin(115200); 15 | Serial.println("Starting BLE ..."); 16 | 17 | BLEDevice::init("ESP32 alerter"); 18 | pServer = BLEDevice::createServer(); 19 | Serial.println("Server created"); 20 | 21 | BLEService *pService = pServer->createService(ALERT_NOTIFICATION_SERVICE_UUID); 22 | Serial.println("Service created"); 23 | 24 | BLECharacteristic *pSupportedAlertCharacteristic = pService->createCharacteristic( 25 | "2A47", // Supported new alert category: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.supported_new_alert_category.xml 26 | BLECharacteristic::PROPERTY_READ 27 | ); 28 | uint8_t simple_alert_val [] = {0x1}; // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.alert_category_id_bit_mask.xml 29 | pSupportedAlertCharacteristic->setValue(simple_alert_val,1); 30 | 31 | 32 | 33 | pNewAlertCharacteristic = pService->createCharacteristic( 34 | "2A46", // New alert: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.new_alert.xml */ 35 | BLECharacteristic::PROPERTY_NOTIFY 36 | ); 37 | 38 | 39 | BLE2902 *p2902 = new BLE2902(); 40 | p2902->setNotifications(true); 41 | pNewAlertCharacteristic->addDescriptor(p2902); 42 | 43 | pService->start(); 44 | Serial.println("Service started"); 45 | 46 | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); 47 | pAdvertising->addServiceUUID(ALERT_NOTIFICATION_SERVICE_UUID); 48 | pAdvertising->setScanResponse(true); 49 | pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue 50 | pAdvertising->setMinPreferred(0x12); 51 | BLEDevice::startAdvertising(); 52 | Serial.println("BLE advertising started."); 53 | } 54 | 55 | // TODO implement 0x2902 to be able to subscribe (Android complains) 56 | // https://play.google.com/store/apps/details?id=com.punchthrough.lightblueexplorer&hl=en_US 57 | 58 | void loop() { 59 | 60 | uint32_t nConnected = pServer->getConnectedCount(); 61 | Serial.println("Connected devices from pServer:" + String(nConnected)); 62 | if(nConnected > 0){ 63 | 64 | char message[] = " Hi there"; 65 | size_t len = strlen(message); 66 | Serial.println("Message length: " + String(len)); 67 | message[0] = 0x00; // Simple alert id https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.alert_category_id.xml 68 | message[1] = 0x01; // one new alert present https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.new_alert.xml 69 | 70 | pNewAlertCharacteristic->setValue((uint8_t*)message, len); //simple alert https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.alert_category_id_bit_mask.xml 71 | pNewAlertCharacteristic->notify(true); 72 | Serial.println("Notification sent"); 73 | } 74 | delay(10000); 75 | } 76 | -------------------------------------------------------------------------------- /06-connectivity-1/src/DHT_Unified_Sensor/DHT_Unified_Sensor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define DHTPIN 5 6 | 7 | #define DHTTYPE DHT22 // DHT 22 (AM2302) 8 | 9 | DHT_Unified dht(DHTPIN, DHTTYPE); 10 | 11 | uint32_t delayMS; 12 | 13 | void setup() { 14 | Serial.begin(115200); 15 | while(!Serial){ 16 | delay(1); 17 | } 18 | Serial.println(F("DHTxx Unified Sensor Example")); 19 | 20 | // Initialize device. 21 | dht.begin(); 22 | Serial.println("Sensor ready"); 23 | // Print temperature sensor details. 24 | sensor_t sensor; 25 | dht.temperature().getSensor(&sensor); 26 | Serial.println(F("------------------------------------")); 27 | Serial.println(F("Temperature Sensor")); 28 | Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); 29 | Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); 30 | Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); 31 | Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("°C")); 32 | Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("°C")); 33 | Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("°C")); 34 | Serial.println(F("------------------------------------")); 35 | // Print humidity sensor details. 36 | dht.humidity().getSensor(&sensor); 37 | Serial.println(F("Humidity Sensor")); 38 | Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); 39 | Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); 40 | Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); 41 | Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("%")); 42 | Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("%")); 43 | Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("%")); 44 | Serial.println(F("------------------------------------")); 45 | // Set delay between sensor readings based on sensor details. 46 | delayMS = sensor.min_delay / 1000; 47 | } 48 | 49 | void loop() { 50 | // Delay between measurements. 51 | delay(delayMS); 52 | // Get temperature event and print its value. 53 | sensors_event_t event; 54 | dht.temperature().getEvent(&event); 55 | if (isnan(event.temperature)) { 56 | Serial.println(F("Error reading temperature!")); 57 | } 58 | else { 59 | Serial.print(F("Temperature: ")); 60 | Serial.print(event.temperature); 61 | Serial.println(F("°C")); 62 | } 63 | // Get humidity event and print its value. 64 | dht.humidity().getEvent(&event); 65 | if (isnan(event.relative_humidity)) { 66 | Serial.println(F("Error reading humidity!")); 67 | } 68 | else { 69 | Serial.print(F("Humidity: ")); 70 | Serial.print(event.relative_humidity); 71 | Serial.println(F("%")); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /06-connectivity-1/src/DS18x20_OneWire/DS18x20_OneWire.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from original OneWire library example 3 | */ 4 | 5 | #include 6 | 7 | #define ONE_WIRE_BUS 0 // D3/GPIO0 on NodeMCU 0.9 8 | 9 | OneWire bus(ONE_WIRE_BUS); 10 | 11 | void setup(void) { 12 | Serial.begin(115200); 13 | while(!Serial){ 14 | delay(1); 15 | } 16 | } 17 | 18 | void loop(void) { 19 | byte i; 20 | byte present = 0; 21 | byte type_s; 22 | byte data[12]; 23 | byte addr[8]; 24 | float celsius, fahrenheit; 25 | 26 | if ( !bus.search(addr)) { 27 | Serial.println("No more addresses."); 28 | Serial.println(); 29 | bus.reset_search(); 30 | delay(250); 31 | return; 32 | } 33 | 34 | Serial.print("ROM ="); 35 | for( i = 0; i < 8; i++) { 36 | Serial.write(' '); 37 | Serial.print(addr[i], HEX); 38 | } 39 | 40 | if (OneWire::crc8(addr, 7) != addr[7]) { 41 | Serial.println("CRC is not valid!"); 42 | return; 43 | } 44 | Serial.println(); 45 | 46 | // the first ROM byte indicates which chip 47 | switch (addr[0]) { 48 | case 0x10: 49 | Serial.println(" Chip = DS18S20"); // or old DS1820 50 | type_s = 1; 51 | break; 52 | case 0x28: 53 | Serial.println(" Chip = DS18B20"); 54 | type_s = 0; 55 | break; 56 | case 0x22: 57 | Serial.println(" Chip = DS1822"); 58 | type_s = 0; 59 | break; 60 | default: 61 | Serial.println("Device is not a DS18x20 family device."); 62 | return; 63 | } 64 | 65 | bus.reset(); 66 | bus.select(addr); 67 | bus.write(0x44, 1); // start conversion, with parasite power on at the end 68 | 69 | delay(1000); // maybe 750ms is enough, maybe not 70 | // we might do a bus.depower() here, but the reset will take care of it. 71 | 72 | present = bus.reset(); 73 | bus.select(addr); 74 | bus.write(0xBE); // Read Scratchpad 75 | 76 | Serial.print(" Data = "); 77 | Serial.print(present, HEX); 78 | Serial.print(" "); 79 | for ( i = 0; i < 9; i++) { // we need 9 bytes 80 | data[i] = bus.read(); 81 | Serial.print(data[i], HEX); 82 | Serial.print(" "); 83 | } 84 | Serial.print(" CRC="); 85 | Serial.print(OneWire::crc8(data, 8), HEX); 86 | Serial.println(); 87 | 88 | // Convert the data to actual temperature 89 | // because the result is a 16 bit signed integer, it should 90 | // be stored to an "int16_t" type, which is always 16 bits 91 | // even when compiled on a 32 bit processor. 92 | int16_t raw = (data[1] << 8) | data[0]; 93 | if (type_s) { 94 | raw = raw << 3; // 9 bit resolution default 95 | if (data[7] == 0x10) { 96 | // "count remain" gives full 12 bit resolution 97 | raw = (raw & 0xFFF0) + 12 - data[6]; 98 | } 99 | } else { 100 | byte cfg = (data[4] & 0x60); 101 | // at lower res, the low bits are undefined, so let's zero them 102 | if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms 103 | else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms 104 | else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms 105 | //// default is 12 bit resolution, 750 ms conversion time 106 | } 107 | celsius = (float)raw / 16.0; 108 | fahrenheit = celsius * 1.8 + 32.0; 109 | Serial.print(" Temperature = "); 110 | Serial.print(celsius); 111 | Serial.print(" Celsius, "); 112 | Serial.print(fahrenheit); 113 | Serial.println(" Fahrenheit"); 114 | } 115 | -------------------------------------------------------------------------------- /06-connectivity-1/src/DS18x20_multiple/DS18x20_multiple.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ONE_WIRE_BUS 0 5 | 6 | OneWire oneWire(ONE_WIRE_BUS); 7 | DallasTemperature sensors(&oneWire); 8 | 9 | int deviceCount = 0; 10 | float tempC; 11 | 12 | void setup(void) 13 | { 14 | Serial.begin(115200); 15 | while(!Serial){ 16 | delay(1); 17 | } 18 | 19 | Serial.println("Starting sensors"); 20 | sensors.begin(); 21 | 22 | Serial.print("Locating devices..."); 23 | deviceCount = sensors.getDeviceCount(); 24 | Serial.println("Found " + String(deviceCount) + " devices"); 25 | } 26 | 27 | void loop(void) 28 | { 29 | sensors.requestTemperatures(); 30 | 31 | for (int i = 0; i < deviceCount; i++){ 32 | tempC = sensors.getTempCByIndex(i); 33 | 34 | Serial.println("Sensor " + String(i+1) + ": " + tempC + " C | " + DallasTemperature::toFahrenheit(tempC) + " F"); 35 | } 36 | 37 | Serial.println(""); 38 | delay(1500); 39 | } 40 | -------------------------------------------------------------------------------- /06-connectivity-1/src/ESP-Now/espnow-receiver.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Rui Santos 3 | Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files. 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | // Structure example to receive data 16 | // Must match the sender structure 17 | typedef struct struct_message { 18 | char a[32]; 19 | int b; 20 | float c; 21 | bool d; 22 | } struct_message; 23 | 24 | // Create a struct_message called myData 25 | struct_message myData; 26 | 27 | // callback function that will be executed when data is received 28 | void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { 29 | memcpy(&myData, incomingData, sizeof(myData)); 30 | Serial.print("Bytes received: "); 31 | Serial.println(len); 32 | Serial.print("Char: "); 33 | Serial.println(myData.a); 34 | Serial.print("Int: "); 35 | Serial.println(myData.b); 36 | Serial.print("Float: "); 37 | Serial.println(myData.c); 38 | Serial.print("Bool: "); 39 | Serial.println(myData.d); 40 | Serial.println(); 41 | } 42 | 43 | void setup() { 44 | // Initialize Serial Monitor 45 | Serial.begin(115200); 46 | 47 | // Set device as a Wi-Fi Station 48 | WiFi.mode(WIFI_STA); 49 | 50 | // Init ESP-NOW 51 | if (esp_now_init() != ESP_OK) { 52 | Serial.println("Error initializing ESP-NOW"); 53 | return; 54 | } 55 | 56 | // Once ESPNow is successfully Init, we will register for recv CB to 57 | // get recv packer info 58 | esp_now_register_recv_cb(OnDataRecv); 59 | } 60 | 61 | void loop() { 62 | 63 | } -------------------------------------------------------------------------------- /06-connectivity-1/src/ESP-Now/espnow-transmitter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Rui Santos 3 | Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files. 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | // REPLACE WITH YOUR RECEIVER MAC Address 16 | // If MAC Address is D4:D4:DA:BD:03:FC, then {0xD4, 0xD4, 0xDA, 0xBD, 0x03, 0xFC} 17 | uint8_t broadcastAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 18 | 19 | // Structure example to send data 20 | // Must match the receiver structure 21 | typedef struct struct_message { 22 | char a[32]; 23 | int b; 24 | float c; 25 | bool d; 26 | } struct_message; 27 | 28 | // Create a struct_message called myData 29 | struct_message myData; 30 | 31 | esp_now_peer_info_t peerInfo; 32 | 33 | // callback when data is sent 34 | void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { 35 | Serial.print("\r\nLast Packet Send Status:\t"); 36 | Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); 37 | } 38 | 39 | void setup() { 40 | // Init Serial Monitor 41 | Serial.begin(115200); 42 | 43 | // Set device as a Wi-Fi Station 44 | WiFi.mode(WIFI_STA); 45 | 46 | // Init ESP-NOW 47 | if (esp_now_init() != ESP_OK) { 48 | Serial.println("Error initializing ESP-NOW"); 49 | return; 50 | } 51 | 52 | // Once ESPNow is successfully Init, we will register for Send CB to 53 | // get the status of Trasnmitted packet 54 | esp_now_register_send_cb(OnDataSent); 55 | 56 | // Register peer 57 | memcpy(peerInfo.peer_addr, broadcastAddress, 6); 58 | peerInfo.channel = 0; 59 | peerInfo.encrypt = false; 60 | 61 | // Add peer 62 | if (esp_now_add_peer(&peerInfo) != ESP_OK){ 63 | Serial.println("Failed to add peer"); 64 | return; 65 | } 66 | } 67 | 68 | void loop() { 69 | // Set values to send 70 | strcpy(myData.a, "Device 1"); 71 | myData.b = random(1,100); 72 | myData.c = 1.2; 73 | myData.d = true; 74 | 75 | // Send message via ESP-NOW 76 | esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); 77 | 78 | if (result == ESP_OK) { 79 | Serial.println("Sent with success"); 80 | } 81 | else { 82 | Serial.println("Error sending the data"); 83 | } 84 | delay(2000); 85 | } -------------------------------------------------------------------------------- /06-connectivity-1/src/ESP-Now/mac-scanner.ino: -------------------------------------------------------------------------------- 1 | #include "WiFi.h" 2 | 3 | void setup(){ 4 | Serial.begin(115200); 5 | WiFi.mode(WIFI_MODE_STA); 6 | Serial.println(WiFi.macAddress()); 7 | } 8 | 9 | void loop(){ 10 | delay(5000); 11 | Serial.println(WiFi.macAddress()); 12 | } -------------------------------------------------------------------------------- /06-connectivity-1/src/hc-12_receiver/hc-12_receiver.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const int RX = D2, TX = D3; // RX and TX pins of HC-12 module 4 | SoftwareSerial HC12(TX, RX); 5 | 6 | void setup() { 7 | HC12.begin(9600); 8 | Serial.begin(9600); 9 | } 10 | 11 | void loop() { 12 | char s; 13 | if (HC12.available();) { 14 | s = HC12.read(); 15 | while (HC12.available()) { 16 | HC12.read(); 17 | } 18 | Serial.println(s); // logs the received data on the serial output 19 | //TODO: make some actions, for example blink the LED based on received data 20 | if ( s == '1') { 21 | } else if ( s == '0') { 22 | } 23 | } 24 | delay(20); 25 | } -------------------------------------------------------------------------------- /06-connectivity-1/src/hc-12_transmitter/hc-12_transmitter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const int RX = D2, TX = D3; // RX and TX pins of HC-12 module 4 | SoftwareSerial HC12(TX, RX); 5 | 6 | void setup() { 7 | HC12.begin(9600); 8 | Serial.begin(9600); 9 | } 10 | 11 | void loop() { 12 | bool sendOne = ((millis() % 5) == 0); // TODO-> use button, not millis() 13 | Serial.print("Sending: "); 14 | Serial.println(sendOne); 15 | if (sendOne) { 16 | HC12.write('1'); 17 | } else { 18 | HC12.write('0'); 19 | } 20 | delay(881); 21 | } -------------------------------------------------------------------------------- /07-connectivity-2/Connectivity2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/07-connectivity-2/Connectivity2.pdf -------------------------------------------------------------------------------- /07-connectivity-2/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | ## HTTP (and different WiFi modes) 3 | - [Station + HTTP client](https://randomnerdtutorials.com/esp32-http-get-post-arduino/) 4 | - You may use the [Yahoo finance endpoint](https://query1.finance.yahoo.com/v8/finance/chart/SAP?interval=1d) 5 | - [Access point + HTTP server](https://randomnerdtutorials.com/esp32-web-server-arduino-ide/) 6 | 7 | ## MQTT 8 | 9 | - [QoS 0 with the knolleary/pubsubclient library](https://github.com/fmi/iot-course/tree/master/08-connectivity-2/src/PubSubClient) 10 | - [QoS 1 with the 256dpi/arduino-mqtt library](https://github.com/fmi/iot-course/tree/master/08-connectivity-2/src/PubSubClient_qos1) 11 | 12 | Use thingsboard server at [tb.genevski.com](tb.genevski.com) for these exercises. You shall setup a device first, using the official [thingsboard helloworld tutorial](https://thingsboard.io/docs/getting-started-guides/helloworld/). It is recommended to first test the MQTT connection [using mosquitto command line client](https://github.com/fmi/iot-course/blob/master/08-connectivity-2/src/mosquitto_examples.md) and only then try with the ESP32 to make it easier to isolate errors. 13 | 14 | > Credentials for [tb.genevski.com](tb.genevski.com) will be provided during the lecture. 15 | -------------------------------------------------------------------------------- /07-connectivity-2/src/01_WIFI_STA/01_WIFI_STA.ino: -------------------------------------------------------------------------------- 1 | #include // https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html 2 | 3 | const char* SSID = "TODO"; 4 | const char* WIFI_PASSWORD = "TODO"; 5 | 6 | 7 | void setup() { 8 | Serial.begin(115200); 9 | while(!Serial); 10 | 11 | WiFi.mode(WIFI_STA); 12 | WiFi.begin(SSID, WIFI_PASSWORD); 13 | 14 | Serial.print("Connecting to WiFi .."); 15 | while (WiFi.status() != WL_CONNECTED) { 16 | Serial.print('.'); 17 | delay(1000); 18 | } 19 | Serial.println("Connected"); 20 | 21 | Serial.print("ESP32 MAC: "); 22 | Serial.println(WiFi.macAddress()); 23 | 24 | Serial.print("Local IP: "); 25 | Serial.println(WiFi.localIP()); 26 | 27 | Serial.print("Subnet mask: "); 28 | Serial.println(WiFi.subnetMask()); 29 | 30 | Serial.print("Gateway IP: "); 31 | Serial.println(WiFi.gatewayIP()); 32 | 33 | Serial.print("Channel: "); 34 | Serial.println(WiFi.channel()); 35 | 36 | Serial.print("DNS: "); 37 | Serial.println(WiFi.dnsIP()); 38 | 39 | Serial.print("TxPower: "); 40 | Serial.println( WiFi.getTxPower()); 41 | 42 | IPAddress resolvedIP; 43 | WiFi.hostByName("google.com", resolvedIP); 44 | Serial.print("Resolved google.com: "); 45 | Serial.println(resolvedIP); 46 | } 47 | 48 | void loop(){ 49 | 50 | Serial.println(WiFi.RSSI()); // -30 to -50 dBm is excellent, -50 to -67 dBm is OK, -67 to -70 dBm shaky 51 | delay(2000); 52 | if (WiFi.status() != WL_CONNECTED) { 53 | Serial.println("Reconnecting..."); 54 | WiFi.disconnect(); 55 | WiFi.reconnect(); 56 | // alternatively, see WiFi.onEvent 57 | // or even simpler, WiFi.setAutoReconnect(true); 58 | } 59 | } -------------------------------------------------------------------------------- /07-connectivity-2/src/02_WIFI_AP/02_WIFI_AP.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char* SSID = "TODO"; 5 | const char* WIFI_PASSWORD = "1234567890"; 6 | 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | while(!Serial); 11 | 12 | 13 | if (!WiFi.softAP(SSID, WIFI_PASSWORD)) { 14 | Serial.println("Soft AP creation failed."); 15 | while(true); 16 | } 17 | 18 | IPAddress access_point_ip = WiFi.softAPIP(); 19 | Serial.print("AP is up. IP: "); 20 | Serial.println(access_point_ip); 21 | } 22 | 23 | void loop(){ 24 | 25 | Serial.print("I am alive: "); 26 | Serial.println(millis()); 27 | delay(1000); 28 | } -------------------------------------------------------------------------------- /07-connectivity-2/src/03_HTTP_Server/03_HTTP_Server.ino: -------------------------------------------------------------------------------- 1 | // inspired by https://lastminuteengineers.com/creating-esp32-web-server-arduino-ide/ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define LED_PIN 17 8 | 9 | const char* SSID = "TODO"; 10 | const char* WIFI_PASSWORD = "1234567890"; 11 | const int PORT = 80; 12 | 13 | bool LED = LOW; 14 | 15 | WebServer server(PORT); 16 | 17 | void setup() { 18 | pinMode(LED_PIN, OUTPUT); 19 | Serial.begin(115200); 20 | while(!Serial); 21 | 22 | 23 | if (!WiFi.softAP(SSID, WIFI_PASSWORD)) { 24 | Serial.println("Soft AP creation failed."); 25 | while(true); 26 | } 27 | 28 | IPAddress access_point_ip = WiFi.softAPIP(); 29 | Serial.print("AP is up. IP: "); 30 | Serial.println(access_point_ip); 31 | 32 | if(!MDNS.begin("ledcontrol")) { // access as a host ledcontrol.local 33 | Serial.println("Error setting up MDNS responder!"); 34 | while(true); 35 | } 36 | Serial.println("MDNS responder started"); 37 | MDNS.addService("_http", "tcp", PORT); // https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html 38 | 39 | server.on("/", handle_root); 40 | server.on("/on", handle_on); 41 | server.on("/off", handle_off); 42 | server.onNotFound(handle_NotFound); 43 | 44 | server.begin(); 45 | Serial.println("Server started on port: " + String(PORT)); 46 | } 47 | 48 | void handle_root() { 49 | server.send(200, "text/html", html_template(LED)); 50 | } 51 | 52 | void handle_on() { 53 | Serial.println("ON"); 54 | LED = HIGH; 55 | server.send(200, "text/html", html_template(LED)); 56 | } 57 | 58 | void handle_off() { 59 | Serial.println("OFF"); 60 | LED = LOW; 61 | server.send(200, "text/html", html_template(LED)); 62 | } 63 | 64 | void handle_NotFound(){ 65 | server.send(404, "text/plain", "Nothing here"); 66 | } 67 | 68 | String html_template(uint8_t led){ 69 | String ptr = " \n"; 70 | ptr +="\n"; 71 | ptr +="LED Controller\n"; 72 | ptr +="\n"; 80 | ptr +="\n"; 81 | ptr +="\n"; 82 | ptr +="

LED controller

\n"; 83 | 84 | if(led){ 85 | ptr +="TURN OFF\n"; 86 | } else { 87 | ptr +="TURN ON\n"; 88 | } 89 | 90 | ptr +="\n"; 91 | ptr +="\n"; 92 | return ptr; 93 | } 94 | 95 | void loop(){ 96 | server.handleClient(); 97 | digitalWrite(LED_PIN, LED); 98 | } -------------------------------------------------------------------------------- /07-connectivity-2/src/04_HTTP_Client/04_HTTP_Client.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // ArduinoJson by Benoit Blanchon... 4 | 5 | const char* SSID = "TODO"; 6 | const char* WIFI_PASSWORD = "TODO"; 7 | 8 | 9 | void setup() { 10 | Serial.begin(115200); 11 | while(!Serial); 12 | 13 | WiFi.mode(WIFI_STA); 14 | WiFi.begin(SSID, WIFI_PASSWORD); 15 | 16 | Serial.print("Connecting to WiFi .."); 17 | while (WiFi.status() != WL_CONNECTED) { 18 | Serial.print('.'); 19 | delay(1000); 20 | } 21 | Serial.println("Connected"); 22 | WiFi.setAutoReconnect(true); 23 | 24 | Serial.print("Local IP: "); 25 | Serial.println(WiFi.localIP()); 26 | } 27 | 28 | void loop(){ 29 | 30 | HTTPClient http; 31 | http.begin("https://api.open-meteo.com/v1/forecast?latitude=42.67&longitude=23.33¤t=temperature_2m,wind_speed_10m,relative_humidity_2m"); 32 | int httpCode = http.GET(); 33 | if (httpCode == HTTP_CODE_OK) { 34 | String payload = http.getString(); 35 | Serial.println(payload); 36 | 37 | JsonDocument doc; // https://arduinojson.org/v7/assistant 38 | DeserializationError error = deserializeJson(doc, payload); 39 | if (error) { 40 | Serial.print("deserializeJson() failed: "); 41 | Serial.println(error.c_str()); 42 | } else { 43 | Serial.println("Elevation: " + String(doc["elevation"])); 44 | 45 | JsonObject current_units = doc["current_units"]; 46 | const char* temperature_unit = current_units["temperature_2m"]; // "°C" 47 | const char* wind_speed_unit = current_units["wind_speed_10m"]; // "km/h" 48 | const char* humidity_unit = current_units["relative_humidity_2m"]; // "%" 49 | 50 | JsonObject current = doc["current"]; 51 | float temperature = current["temperature_2m"]; // 6.3 52 | int wind_speed = current["wind_speed_10m"]; // 12 53 | int humidity = current["relative_humidity_2m"]; // 44 54 | Serial.println(String(temperature) + temperature_unit + ", " + String(wind_speed) + wind_speed_unit + ", " + String(humidity) + humidity_unit); 55 | 56 | } 57 | 58 | 59 | } else { 60 | Serial.println("Request failed: " + String(httpCode)); 61 | } 62 | 63 | delay(120 * 1000); // do not flood the API with too many requests 64 | 65 | } -------------------------------------------------------------------------------- /07-connectivity-2/src/05_PubSubClient/05_PubSubClient.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include //https://github.com/knolleary/pubsubclient/blob/master/src/PubSubClient.cpp 3 | 4 | const char* mqtt_server = "test.mosquitto.org"; 5 | const int mqtt_port = 1883; 6 | const char* clientId = "DoesntMatter98327988982385729834028"; 7 | // const char* user = "rw"; 8 | // const char* pass = "readwrite"; 9 | 10 | WiFiClient wifi; 11 | PubSubClient client(wifi); 12 | 13 | void setup_wifi() { 14 | WiFi.begin("btc123", "whishiknewit"); 15 | Serial.println("Connecting to wifi "); 16 | while (WiFi.status() != WL_CONNECTED) { 17 | delay(1000); 18 | Serial.print("."); 19 | } 20 | Serial.print("Connected. IP: "); 21 | Serial.println(WiFi.localIP()); 22 | } 23 | 24 | void callback(char* topic, byte* payload, unsigned int length) { 25 | Serial.print("Message received on topic [" + String(topic) + "]"); 26 | for (int i = 0; i < length; i++) { 27 | Serial.print((char)payload[i]); 28 | } 29 | Serial.println(); 30 | } 31 | 32 | int reconnect() { 33 | Serial.println("Reconnect requested"); 34 | if(client.connected()) { 35 | Serial.println("MQTT client is still connected"); 36 | return 0; 37 | } 38 | 39 | Serial.print("Reconnecting to MQTT server..."); 40 | // if (client.connect(clientId, user, pass)) { 41 | if(client.connect(clientId)) { 42 | Serial.println("connected"); 43 | 44 | client.subscribe("v1/devices/me/telemetry"); 45 | Serial.println("resubscribed"); 46 | return 0; 47 | 48 | } else { 49 | Serial.println("failed"); 50 | return client.state(); 51 | } 52 | } 53 | 54 | void setup() { 55 | Serial.begin(115200); 56 | randomSeed(analogRead(0)); 57 | 58 | setup_wifi(); 59 | 60 | client.setServer(mqtt_server, mqtt_port); 61 | client.setCallback(callback); 62 | } 63 | 64 | void loop() { 65 | 66 | float temperature = random(200, 301) / 10.0; 67 | 68 | int err = reconnect(); 69 | if(err != 0){ 70 | // TODO buffer the measurement to send next time 71 | Serial.println("Could not reconnect"); 72 | } else { 73 | client.loop(); // process incoming messages and maintain connection to server 74 | 75 | // TODO add sequence number 76 | String json = "{\"temperature\":" + String(temperature,1) + "}"; 77 | // Serial.println(json); 78 | client.publish("v1/devices/me/telemetry", json.c_str()); 79 | 80 | } 81 | delay(2000); 82 | } 83 | -------------------------------------------------------------------------------- /07-connectivity-2/src/06_ArduinoMQTT_qos1/06_ArduinoMQTT_qos1.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include // https://github.com/256dpi/arduino-mqtt (MQTT by Joel Gaehwiler) 3 | 4 | const char* mqtt_server = "test.mosquitto.org"; 5 | const char* clientId = "DoesntMatter9754239082470293742042122"; 6 | // const char* user = "niceaccesstoken2022"; 7 | // const char* pass = NULL; 8 | 9 | WiFiClient wifi; 10 | MQTTClient client; 11 | 12 | void setup_wifi() { 13 | WiFi.begin("btc123", "iwhishiknewthat"); 14 | Serial.println("Connecting to wifi "); 15 | while (WiFi.status() != WL_CONNECTED) { 16 | delay(1000); 17 | Serial.print("."); 18 | } 19 | Serial.print("Connected. IP: "); 20 | Serial.println(WiFi.localIP()); 21 | } 22 | 23 | void messageReceived(String &topic, String &payload) { 24 | Serial.println("incoming: " + topic + " - " + payload); 25 | } 26 | 27 | bool reconnect() { 28 | Serial.println("Reconnect requested"); 29 | if(client.connected()) { 30 | Serial.println("MQTT client is still connected"); 31 | return true; 32 | } 33 | 34 | Serial.print("Reconnecting to MQTT server..."); 35 | // if(client.connect(clientId, user, pass)) { 36 | if(client.connect(clientId)) { 37 | Serial.println("connected"); 38 | 39 | client.subscribe("v1/devices/me/telemetry"); 40 | Serial.println("resubscribed"); 41 | return true; 42 | 43 | } else { 44 | Serial.println("failed"); 45 | lwmqtt_err_t err = client.lastError(); 46 | Serial.println(err); 47 | 48 | lwmqtt_return_code_t ret = client.returnCode(); 49 | Serial.println(ret); 50 | return false; 51 | } 52 | } 53 | 54 | void setup() { 55 | Serial.begin(115200); 56 | randomSeed(analogRead(0)); 57 | 58 | setup_wifi(); 59 | 60 | client.onMessage(messageReceived); 61 | client.begin(mqtt_server, wifi); 62 | } 63 | 64 | void loop() { 65 | 66 | float temperature = random(200, 301) / 10.0; 67 | 68 | if(!reconnect()){ 69 | // TODO buffer the measurement to send next time 70 | } else { 71 | client.loop(); // process incoming messages and maintain connection to server 72 | delay(10); 73 | 74 | // TODO add sequence number 75 | String json = "{\"temperature\":" + String(temperature,1) + "}"; 76 | // Serial.println(json); 77 | 78 | int qos = 1; 79 | bool retained = false; 80 | bool success = client.publish("v1/devices/me/telemetry", json.c_str(), retained, qos); 81 | if(!success){ 82 | Serial.println("publish failed"); 83 | lwmqtt_err_t err = client.lastError(); // https://github.com/256dpi/arduino-mqtt/blob/master/src/lwmqtt/lwmqtt.h 84 | Serial.println(err); 85 | } 86 | } 87 | delay(2000); 88 | } 89 | -------------------------------------------------------------------------------- /07-connectivity-2/src/old/HttpServer/HttpServer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | const char* ssid = "btc123"; 10 | const char* password = "iwhichiknewthat"; 11 | 12 | WebServer server(80); 13 | 14 | float temperature = 0.0; 15 | int humidity = 50; 16 | 17 | void setupWiFi(){ 18 | Serial.println("Setting up wifi"); 19 | WiFi.mode(WIFI_STA); 20 | WiFi.begin(ssid, password); 21 | 22 | while (WiFi.status() != WL_CONNECTED) { 23 | delay(1000); 24 | Serial.print("."); 25 | } 26 | Serial.println(""); 27 | Serial.print("Connected to "); 28 | Serial.println(ssid); 29 | Serial.print("IP address: "); 30 | Serial.println(WiFi.localIP()); 31 | } 32 | 33 | 34 | void setupFS(){ 35 | if(!SPIFFS.begin()){ 36 | Serial.println("Cannot start SPIFFS"); 37 | return; 38 | } 39 | Serial.println("SPIFFS ready"); 40 | 41 | File file = SPIFFS.open("/index.html", "r"); 42 | if(!file){ 43 | Serial.println("Cannot open index.html"); 44 | } 45 | } 46 | 47 | 48 | void handleHome(){ 49 | server.send(200, "text/html", "I am alive"); // TODO serve html from SPIFFS 50 | } 51 | 52 | 53 | void handleMeasurements() { 54 | 55 | String response = "{"; 56 | 57 | response+= "\"temperature\":" + String(temperature); 58 | response+= ",\"humidity\":" + String(humidity); 59 | 60 | response+="}"; 61 | server.sendHeader("Access-Control-Allow-Origin", "*", true); // for browser testing 62 | server.send(200, "text/json", response); 63 | } 64 | 65 | 66 | void handleNotFound(){ 67 | server.send(404, "text/plain", "Not found"); 68 | } 69 | 70 | 71 | void setupRoutes(){ 72 | server.on("/", HTTP_GET, handleHome); 73 | server.on("/measurements", HTTP_GET, handleMeasurements); 74 | 75 | server.onNotFound(handleNotFound); 76 | 77 | server.begin(); 78 | Serial.println("HTTP server ready"); 79 | } 80 | 81 | 82 | void setup() { 83 | Serial.begin(115200); 84 | while (!Serial) { 85 | delay(1); 86 | } 87 | Serial.println("Serial ready"); 88 | 89 | setupWiFi(); 90 | setupRoutes(); 91 | setupFS(); 92 | } 93 | 94 | 95 | void loop() { 96 | temperature = random(200, 300) / 10.0; 97 | humidity = random(30, 80); 98 | 99 | server.handleClient(); 100 | delay(100); 101 | } -------------------------------------------------------------------------------- /07-connectivity-2/src/old/mosquitto/mosquitto.conf: -------------------------------------------------------------------------------- 1 | #persistence true 2 | #persistence_location /mosquitto/data/ 3 | 4 | #log_type all 5 | 6 | ## Non-SSL listener 7 | listener 1883 8 | 9 | ## SSL listener 10 | listener 8883 11 | protocol mqtt 12 | cafile /mosquitto/config/fullchain.pem 13 | keyfile /mosquitto/config/privkey.pem 14 | certfile /mosquitto/config/cert.pem 15 | tls_version tlsv1.2 16 | 17 | ## Websocket (SSL) listener 18 | listener 8083 19 | protocol websockets 20 | cafile /mosquitto/config/fullchain.pem 21 | keyfile /mosquitto/config/privkey.pem 22 | certfile /mosquitto/config/cert.pem 23 | tls_version tlsv1.2 24 | 25 | # Authentication 26 | allow_anonymous false 27 | password_file /mosquitto/config/passwd 28 | 29 | ## Client certificate 30 | require_certificate false -------------------------------------------------------------------------------- /07-connectivity-2/src/old/mosquitto/mosquitto.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | mosquitto: 5 | image: eclipse-mosquitto 6 | ports: 7 | - 1883:1883 8 | - 8883:8883 9 | - 8083:8083 10 | volumes: 11 | - ./mosquitto.conf:/mosquitto/config/mosquitto.conf 12 | - ./passwd:/mosquitto/config/passwd 13 | - /etc/letsencrypt/live/mqtt.genevski.com/cert.pem:/mosquitto/config/cert.pem 14 | - /etc/letsencrypt/live/mqtt.genevski.com/privkey.pem:/mosquitto/config/privkey.pem 15 | - /etc/letsencrypt/live/mqtt.genevski.com/chain.pem:/mosquitto/config/chain.pem 16 | - /etc/letsencrypt/live/mqtt.genevski.com/fullchain.pem:/mosquitto/config/fullchain.pem 17 | - mosquitto-data:/mosquitto/data 18 | 19 | volumes: 20 | mosquitto-data: -------------------------------------------------------------------------------- /07-connectivity-2/src/old/mosquitto/passwd: -------------------------------------------------------------------------------- 1 | username1:$6$XIB+89wNWNmrgMSl$sPG67yMa+QC5bcg/c2DEaH1QCljw+SPMwEUO90lk3iWmF3lm/lM9flbV0jgqFjq7fvK5MqxoBaT8O236+lyFjQ== 2 | username2:$6$YV9oxyZkFxRkzFG8$6N3DFTD5gh/xFLZAlJafxVw04n04amA/0lIAWa4vqvvZOuC8dWBZD1/UWGIbdGMLmYOSNWRG2KU9bu3D71pkhA== 3 | username3:$6$aBV6X2p69aslOwgh$IajN2iL3BfnS2MVZhJTsZg4d7a6tolNRHPw50suVf2b2ekcJ6nVJVKNWu0WR6GsngAjAxUCR9tsTaWSHPbqMbA== 4 | -------------------------------------------------------------------------------- /07-connectivity-2/src/old/mosquitto_examples.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | This guide has some popular mosquitto commands that have been tested with the course setup at [tb.genevski.com](tb.genevski.com). We have only tested them on Ubuntu. 3 | 4 | # Installation 5 | Mosquitto is usually distributed through two packages, `mosquitto` and `mosquitto-clients`. If you don't need to run your own server, you can install the second package only. Have a look at [this installation guide for Ubuntu](http://www.steves-internet-guide.com/install-mosquitto-linux/) 6 | 7 | # Clients 8 | ## Command line 9 | Mosquitto installation comes with several commands that can be used for testing the protocol. 10 | 11 | ### Subscribing 12 | To subscribe to a hypothetical topic `topics/1` on a localhost sever you only need to provide the topic URL: 13 | ```bash 14 | mosquitto_sub --url mqtt://localhost:1883/topic/1 15 | ``` 16 | > Full URL option format is: `mqtt://[username[:password]@]host[:port]/topic -u username -P password` 17 | 18 | ### Publishing 19 | Publishing requires more options, such as QoS and message payload: 20 | ```bash 21 | mosquitto_pub --url mqtt://localhost:1883/topic/1 -m 32 -q 0 22 | ``` 23 | 24 | To publish to the provided [tb.genevski.com](tb.genevski.com) MQTT service you need even more options: 25 | 26 | - Using non-encrypted TCP connection: 27 | ```bash 28 | mosquitto_pub -d -q 1 -h tb.genevski.com -p "1883" -t "v1/devices/me/telemetry" -u youraccesstoken -m {"temperature":25.1} 29 | ``` 30 | 31 | - Using encrypted (TLS) TCP connection 32 | ```bash 33 | mosquitto_pub -d -q 1 -h tb.genevski.com -p "8883" -t "v1/devices/me/telemetry" -u youraccesstoken --capath /etc/ssl/certs/ -m {"temperature":25.3} 34 | ``` 35 | 36 | > WARNING - this has only been tested on Ubuntu and may not work for other distros. You can add either the `--cafile` or `--capath` options as per the [official documentation](https://mosquitto.org/man/mosquitto_pub-1.html), but nevertheless still get SSL handshape errors if your cert store doesn't trust the certificate provider. 37 | 38 | 39 | ## Websockets client 40 | You can use the [live Eclipse Paho client](https://www.eclipse.org/paho/clients/js/utility/) to test websocket communication. 41 | 42 | 43 | ## ESP32 / ESP8266 44 | 45 | - [QoS 0 with the knolleary/pubsubclient library](https://github.com/fmi/iot-course/tree/master/07-connectivity-2/src/PubSubClient) 46 | - [QoS 1 with the 256dpi/arduino-mqtt library](https://github.com/fmi/iot-course/tree/master/07-connectivity-2/src/PubSubClient_qos1) 47 | 48 | 49 | # Running a mosquitto server through docker 50 | If you nevertheless need to run a mosquitto server, you can look at the really simple setup in the provided [`mosquitto.yml`](mosquitto/mosquitto.yml), which runs in docker swarm / docker compose. 51 | 52 | ### Generating passwords 53 | One option to supply user accounts to mosquitto is through a `passwd` file. This script can be used to create/update the password for a given user, provided that the `passwd` file is in the current directory. 54 | 55 | ```bash 56 | docker run -it -v $(pwd):/mnt/tmp eclipse-mosquitto mosquitto_passwd /mnt/tmp/passwd username1 57 | ``` 58 | 59 | > NOTE: the passwd file given in this repo is only an example of what you should expect inside it. Please generate your own file. 60 | 61 | ### Server configuration 62 | Server configuration has been provided in the given `mosquitto.conf` and `mosquitto.yml` files. 63 | 64 | References: 65 | - https://mosquitto.org/man/mosquitto_passwd-1.html 66 | - https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04 67 | -------------------------------------------------------------------------------- /08-power-management/08-power management.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/08-power-management/08-power management.pdf -------------------------------------------------------------------------------- /08-power-management/deep_sleep/deep_sleep.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Deep Sleep with Touch Wake Up 3 | ===================================== 4 | This code displays how to use deep sleep with 5 | a touch as a wake up source and how to store data in 6 | RTC memory to use it over reboots 7 | 8 | ESP32 can have multiple touch pads enabled as wakeup source 9 | ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled 10 | 11 | This code is under Public Domain License. 12 | 13 | Author: 14 | Pranav Cherukupalli 15 | */ 16 | 17 | #if CONFIG_IDF_TARGET_ESP32 18 | #define THRESHOLD 40 /* Greater the value, more the sensitivity */ 19 | #elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) 20 | #define THRESHOLD 5000 /* Lower the value, more the sensitivity */ 21 | #else // ESP32-P4 + default for other chips (to be adjusted) */ 22 | #define THRESHOLD 500 /* Lower the value, more the sensitivity */ 23 | #endif 24 | 25 | RTC_DATA_ATTR int bootCount = 0; 26 | touch_pad_t touchPin; 27 | /* 28 | Method to print the reason by which ESP32 29 | has been awaken from sleep 30 | */ 31 | void print_wakeup_reason() { 32 | esp_sleep_wakeup_cause_t wakeup_reason; 33 | 34 | wakeup_reason = esp_sleep_get_wakeup_cause(); 35 | 36 | switch (wakeup_reason) { 37 | case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break; 38 | case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; 39 | case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break; 40 | case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break; 41 | case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break; 42 | default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break; 43 | } 44 | } 45 | 46 | /* 47 | Method to print the touchpad by which ESP32 48 | has been awaken from sleep 49 | */ 50 | void print_wakeup_touchpad() { 51 | touchPin = esp_sleep_get_touchpad_wakeup_status(); 52 | 53 | #if CONFIG_IDF_TARGET_ESP32 54 | switch (touchPin) { 55 | case 0: Serial.println("Touch detected on GPIO 4"); break; 56 | case 1: Serial.println("Touch detected on GPIO 0"); break; 57 | case 2: Serial.println("Touch detected on GPIO 2"); break; 58 | case 3: Serial.println("Touch detected on GPIO 15"); break; 59 | case 4: Serial.println("Touch detected on GPIO 13"); break; 60 | case 5: Serial.println("Touch detected on GPIO 12"); break; 61 | case 6: Serial.println("Touch detected on GPIO 14"); break; 62 | case 7: Serial.println("Touch detected on GPIO 27"); break; 63 | case 8: Serial.println("Touch detected on GPIO 33"); break; 64 | case 9: Serial.println("Touch detected on GPIO 32"); break; 65 | default: Serial.println("Wakeup not by touchpad"); break; 66 | } 67 | #else 68 | if (touchPin < TOUCH_PAD_MAX) { 69 | Serial.printf("Touch detected on GPIO %d\n", touchPin); 70 | } else { 71 | Serial.println("Wakeup not by touchpad"); 72 | } 73 | #endif 74 | } 75 | 76 | void setup() { 77 | Serial.begin(115200); 78 | delay(1000); //Take some time to open up the Serial Monitor 79 | 80 | //Increment boot number and print it every reboot 81 | ++bootCount; 82 | Serial.println("Boot number: " + String(bootCount)); 83 | 84 | //Print the wakeup reason for ESP32 and touchpad too 85 | print_wakeup_reason(); 86 | print_wakeup_touchpad(); 87 | 88 | #if CONFIG_IDF_TARGET_ESP32 89 | //Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27) 90 | touchSleepWakeUpEnable(T3, THRESHOLD); 91 | touchSleepWakeUpEnable(T7, THRESHOLD); 92 | 93 | #else //ESP32-S2 + ESP32-S3 + ESP32-P4 94 | //Setup sleep wakeup on Touch Pad 3 (GPIO3) 95 | touchSleepWakeUpEnable(T3, THRESHOLD); 96 | 97 | #endif 98 | 99 | //Go to sleep now 100 | Serial.println("Going to sleep now"); 101 | esp_deep_sleep_start(); 102 | Serial.println("This will never be printed"); 103 | } 104 | 105 | void loop() { 106 | //This will never be reached 107 | } 108 | -------------------------------------------------------------------------------- /08-power-management/deep_sleep/deep_sleep.md: -------------------------------------------------------------------------------- 1 | ## *ESP32 Deep Sleep and Wake Up Sources* 2 | 3 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 4 | 5 | ## Schematic and connections 6 | 7 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 8 | 9 | - Schematic is [here](images/schematic_stepper.png). 10 | 11 | - We'll connect a m/f wire to _GPIO15_ 12 | 13 | ![alt text](images/deep_sleep_touch.png) 14 | 15 | 16 | ## Code to Run (Arduino Sketches) 17 | 18 | 1. Run this sketch in Arduino IDE, compile it and and upload it to the board. It will print to the serial monitor "Wakeup signals..." and what coused them. 19 | ```cpp 20 | /* 21 | Deep Sleep with Touch Wake Up 22 | ===================================== 23 | This code displays how to use deep sleep with 24 | a touch as a wake up source and how to store data in 25 | RTC memory to use it over reboots 26 | 27 | ESP32 can have multiple touch pads enabled as wakeup source 28 | ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled 29 | 30 | This code is under Public Domain License. 31 | 32 | Author: 33 | Pranav Cherukupalli 34 | */ 35 | 36 | #if CONFIG_IDF_TARGET_ESP32 37 | #define THRESHOLD 40 /* Greater the value, more the sensitivity */ 38 | #elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) 39 | #define THRESHOLD 5000 /* Lower the value, more the sensitivity */ 40 | #else // ESP32-P4 + default for other chips (to be adjusted) */ 41 | #define THRESHOLD 500 /* Lower the value, more the sensitivity */ 42 | #endif 43 | 44 | RTC_DATA_ATTR int bootCount = 0; 45 | touch_pad_t touchPin; 46 | /* 47 | Method to print the reason by which ESP32 48 | has been awaken from sleep 49 | */ 50 | void print_wakeup_reason() { 51 | esp_sleep_wakeup_cause_t wakeup_reason; 52 | 53 | wakeup_reason = esp_sleep_get_wakeup_cause(); 54 | 55 | switch (wakeup_reason) { 56 | case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break; 57 | case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; 58 | case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break; 59 | case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break; 60 | case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break; 61 | default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break; 62 | } 63 | } 64 | 65 | /* 66 | Method to print the touchpad by which ESP32 67 | has been awaken from sleep 68 | */ 69 | void print_wakeup_touchpad() { 70 | touchPin = esp_sleep_get_touchpad_wakeup_status(); 71 | 72 | #if CONFIG_IDF_TARGET_ESP32 73 | switch (touchPin) { 74 | case 0: Serial.println("Touch detected on GPIO 4"); break; 75 | case 1: Serial.println("Touch detected on GPIO 0"); break; 76 | case 2: Serial.println("Touch detected on GPIO 2"); break; 77 | case 3: Serial.println("Touch detected on GPIO 15"); break; 78 | case 4: Serial.println("Touch detected on GPIO 13"); break; 79 | case 5: Serial.println("Touch detected on GPIO 12"); break; 80 | case 6: Serial.println("Touch detected on GPIO 14"); break; 81 | case 7: Serial.println("Touch detected on GPIO 27"); break; 82 | case 8: Serial.println("Touch detected on GPIO 33"); break; 83 | case 9: Serial.println("Touch detected on GPIO 32"); break; 84 | default: Serial.println("Wakeup not by touchpad"); break; 85 | } 86 | #else 87 | if (touchPin < TOUCH_PAD_MAX) { 88 | Serial.printf("Touch detected on GPIO %d\n", touchPin); 89 | } else { 90 | Serial.println("Wakeup not by touchpad"); 91 | } 92 | #endif 93 | } 94 | 95 | void setup() { 96 | Serial.begin(115200); 97 | delay(1000); //Take some time to open up the Serial Monitor 98 | 99 | //Increment boot number and print it every reboot 100 | ++bootCount; 101 | Serial.println("Boot number: " + String(bootCount)); 102 | 103 | //Print the wakeup reason for ESP32 and touchpad too 104 | print_wakeup_reason(); 105 | print_wakeup_touchpad(); 106 | 107 | #if CONFIG_IDF_TARGET_ESP32 108 | //Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27) 109 | touchSleepWakeUpEnable(T3, THRESHOLD); 110 | touchSleepWakeUpEnable(T7, THRESHOLD); 111 | 112 | #else //ESP32-S2 + ESP32-S3 + ESP32-P4 113 | //Setup sleep wakeup on Touch Pad 3 (GPIO3) 114 | touchSleepWakeUpEnable(T3, THRESHOLD); 115 | 116 | #endif 117 | 118 | //Go to sleep now 119 | Serial.println("Going to sleep now"); 120 | esp_deep_sleep_start(); 121 | Serial.println("This will never be printed"); 122 | } 123 | 124 | void loop() { 125 | //This will never be reached 126 | } 127 | 128 | ``` 129 | -------------------------------------------------------------------------------- /08-power-management/deep_sleep/images/deep_sleep_touch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/08-power-management/deep_sleep/images/deep_sleep_touch.png -------------------------------------------------------------------------------- /08-power-management/sleep_modes/images/power_modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/08-power-management/sleep_modes/images/power_modes.png -------------------------------------------------------------------------------- /08-power-management/sleep_modes/images/wiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/08-power-management/sleep_modes/images/wiring.jpg -------------------------------------------------------------------------------- /08-power-management/sleep_modes/power_modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/08-power-management/sleep_modes/power_modes.png -------------------------------------------------------------------------------- /09-security/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | ## Encryption 4 | ### HTTPS 5 | Implement a [full verification client](src/01_HTTP_W_WiFiClientSecure) with **ESP32**. This is an extention of a previous exercise, that adds https. 6 | 7 | If things don't work, you can test the connection `curl`: 8 | ```bash 9 | curl -v -X GET "https://api.open-meteo.com/v1/forecast?latitude=42.67&longitude=23.33¤t=temperature_2m,wind_speed_10m,relative_humidity_2m" 10 | ``` 11 | 12 | ### MQTTS 13 | Connect to the MQTT endpoint from the previous exercises, but this time [over TLS](src/02_MQTTS) 14 | 15 | To figure out if the problem is in your code or the connection, you can test with the excellent [MQTTX tool](https://mqttx.app/). 16 | 17 | ### OAuth2 code flow 18 | Authorize and connect the board to your github account using [OAuth device code flow](src/03_OAuth_Device_Flow). 19 | 20 | 21 | ## Reverse engineering with Signal Analyzer 22 | Record and decode the OneWire signal from DS18B20 communication using a signal analyzer. 23 | 24 | # References 25 | * [Wifi network geolocation](https://wigle.net/) 26 | * [Signal analyzer - Saleae](https://www.saleae.com/downloads) 27 | * [ESP32 exploit of Flash Encryption and Sec. Boot Keys Extraction](https://limitedresults.com/2019/11/pwn-the-esp32-forever-flash-encryption-and-sec-boot-keys-extraction/) 28 | -------------------------------------------------------------------------------- /09-security/Security.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/09-security/Security.pdf -------------------------------------------------------------------------------- /09-security/mosquitto.org.crt: -------------------------------------------------------------------------------- 1 | "-----BEGIN CERTIFICATE-----\n" \ 2 | "MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL\n" \ 3 | "BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG\n" \ 4 | "A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU\n" \ 5 | "BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv\n" \ 6 | "by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE\n" \ 7 | "BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES\n" \ 8 | "MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp\n" \ 9 | "dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ\n" \ 10 | "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg\n" \ 11 | "UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW\n" \ 12 | "Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA\n" \ 13 | "s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH\n" \ 14 | "3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo\n" \ 15 | "E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT\n" \ 16 | "MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV\n" \ 17 | "6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n" \ 18 | "BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC\n" \ 19 | "6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf\n" \ 20 | "+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK\n" \ 21 | "sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839\n" \ 22 | "LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE\n" \ 23 | "m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=\n" \ 24 | "-----END CERTIFICATE-----\n" 25 | -------------------------------------------------------------------------------- /09-security/src/01_HTTP_W_WiFiClientSecure/01_HTTP_W_WiFiClientSecure.ino: -------------------------------------------------------------------------------- 1 | // HTTP client with WiFiClientSecure 2 | #include 3 | #include 4 | #include // ArduinoJson by Benoit Blanchon... 5 | #include 6 | #include 7 | 8 | const char* SSID = "......."; // your network SSID (name) 9 | const char* WIFI_PASSWORD = ".........."; // your network password 10 | 11 | // The root CA certificate for the server 12 | const char* rootCACertificate = \ 13 | "-----BEGIN CERTIFICATE-----\n" \ 14 | "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \ 15 | "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \ 16 | "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \ 17 | "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \ 18 | "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \ 19 | "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \ 20 | "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \ 21 | "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \ 22 | "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \ 23 | "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \ 24 | "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \ 25 | "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \ 26 | "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \ 27 | "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \ 28 | "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \ 29 | "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \ 30 | "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \ 31 | "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \ 32 | "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \ 33 | "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \ 34 | "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \ 35 | "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \ 36 | "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \ 37 | "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \ 38 | "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \ 39 | "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \ 40 | "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \ 41 | "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \ 42 | "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \ 43 | "-----END CERTIFICATE-----\n"; 44 | 45 | 46 | void setup() { 47 | Serial.begin(115200); 48 | while(!Serial); 49 | 50 | WiFi.mode(WIFI_STA); 51 | WiFi.begin(SSID, WIFI_PASSWORD); 52 | 53 | Serial.print("Connecting to WiFi .."); 54 | while (WiFi.status() != WL_CONNECTED) { 55 | Serial.print('.'); 56 | delay(1000); 57 | } 58 | Serial.println("Connected"); 59 | WiFi.setAutoReconnect(true); 60 | 61 | Serial.print("Local IP: "); 62 | Serial.println(WiFi.localIP()); 63 | } 64 | 65 | void loop(){ 66 | WiFiClientSecure *client = new WiFiClientSecure; 67 | if(client) { 68 | // set secure client with certificate 69 | client->setCACert(rootCACertificate); 70 | //create an HTTPClient instance 71 | HTTPClient https; 72 | 73 | https.begin(*client, "https://api.open-meteo.com/v1/forecast?latitude=42.67&longitude=23.33¤t=temperature_2m,wind_speed_10m,relative_humidity_2m"); 74 | int httpCode = https.GET(); 75 | if (httpCode == HTTP_CODE_OK) { 76 | Serial.printf("[HTTPS] GET... code: %d\n", httpCode); 77 | String payload = https.getString(); 78 | Serial.println(payload); 79 | 80 | JsonDocument doc; // https://arduinojson.org/v7/assistant 81 | DeserializationError error = deserializeJson(doc, payload); 82 | if (error) { 83 | Serial.print("deserializeJson() failed: "); 84 | Serial.println(error.c_str()); 85 | } else { 86 | Serial.println("Elevation: " + String(doc["elevation"])); 87 | 88 | JsonObject current_units = doc["current_units"]; 89 | const char* temperature_unit = current_units["temperature_2m"]; // "°C" 90 | const char* wind_speed_unit = current_units["wind_speed_10m"]; // "km/h" 91 | const char* humidity_unit = current_units["relative_humidity_2m"]; // "%" 92 | 93 | JsonObject current = doc["current"]; 94 | float temperature = current["temperature_2m"]; // 6.3 95 | int wind_speed = current["wind_speed_10m"]; // 12 96 | int humidity = current["relative_humidity_2m"]; // 44 97 | Serial.println(String(temperature) + temperature_unit + ", " + String(wind_speed) + wind_speed_unit + ", " + String(humidity) + humidity_unit); 98 | 99 | } 100 | 101 | 102 | } else { 103 | Serial.println("Request failed: " + String(httpCode)); 104 | } 105 | 106 | delay(120 * 1000); // do not flood the API with too many requests 107 | 108 | } 109 | } -------------------------------------------------------------------------------- /09-security/src/01_HTTP_W_WiFiClientSecure/ISRGRootX1_ОМ.pem: -------------------------------------------------------------------------------- 1 | "-----BEGIN CERTIFICATE-----\n" \ 2 | "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \ 3 | "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \ 4 | "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \ 5 | "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \ 6 | "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \ 7 | "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \ 8 | "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \ 9 | "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \ 10 | "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \ 11 | "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \ 12 | "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \ 13 | "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \ 14 | "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \ 15 | "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \ 16 | "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \ 17 | "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \ 18 | "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \ 19 | "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \ 20 | "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \ 21 | "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \ 22 | "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \ 23 | "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \ 24 | "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \ 25 | "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \ 26 | "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \ 27 | "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \ 28 | "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \ 29 | "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \ 30 | "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \ 31 | "-----END CERTIFICATE-----\n" 32 | -------------------------------------------------------------------------------- /09-security/src/02_MQTTS/02_MQTTS.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // WiFi credentials 6 | const char* ssid = "......."; 7 | const char* password = "......."; 8 | 9 | // MQTT broker details 10 | const char* mqtt_server = "test.mosquitto.org"; 11 | const int mqtt_port = 8885; // Encrypted and authenticated MQTT port 12 | const char* clientId = "DoesntMatter98327988982385729834028"; 13 | const char* user = "rw"; // Predefined username 14 | const char* pass = "readwrite"; // Predefined password 15 | 16 | // Root CA certificate for test.mosquitto.org 17 | const char* root_ca = \ 18 | "-----BEGIN CERTIFICATE-----\n"\ 19 | "MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL\n" \ 20 | "BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG\n" \ 21 | "A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU\n" \ 22 | "BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv\n" \ 23 | "by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE\n" \ 24 | "BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES\n" \ 25 | "MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp\n" \ 26 | "dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ\n" \ 27 | "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg\n" \ 28 | "UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW\n" \ 29 | "Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA\n" \ 30 | "s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH\n" \ 31 | "3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo\n" \ 32 | "E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT\n" \ 33 | "MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV\n" \ 34 | "6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n" \ 35 | "BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC\n" \ 36 | "6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf\n" \ 37 | "+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK\n" \ 38 | "sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839\n" \ 39 | "LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE\n" \ 40 | "m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=\n" \ 41 | "-----END CERTIFICATE-----\n"; 42 | 43 | WiFiClientSecure wifiClient; 44 | PubSubClient client(wifiClient); 45 | 46 | void setup_wifi() { 47 | WiFi.begin(ssid, password); 48 | Serial.println("Connecting to WiFi..."); 49 | while (WiFi.status() != WL_CONNECTED) { 50 | delay(1000); 51 | Serial.print("."); 52 | } 53 | Serial.println("\nConnected to WiFi"); 54 | 55 | wifiClient.setCACert(root_ca); // Set the root CA certificate 56 | } 57 | 58 | void callback(char* topic, byte* payload, unsigned int length) { 59 | Serial.print("Message received on topic: "); 60 | Serial.println(topic); 61 | Serial.print("Message: "); 62 | for (int i = 0; i < length; i++) { 63 | Serial.print((char)payload[i]); 64 | } 65 | Serial.println(); 66 | } 67 | 68 | int reconnect() { 69 | Serial.println("Reconnect requested"); 70 | if(client.connected()) { 71 | Serial.println("MQTT client is still connected"); 72 | return 0; 73 | } 74 | 75 | Serial.print("Reconnecting to MQTT server..."); 76 | // if (client.connect(clientId, user, pass)) { 77 | if(client.connect(clientId, user, pass)) { 78 | Serial.println("connected"); 79 | 80 | client.subscribe("v1/devices/me/telemetry"); 81 | Serial.println("resubscribed"); 82 | return 0; 83 | 84 | } else { 85 | Serial.println("failed"); 86 | return client.state(); 87 | } 88 | } 89 | 90 | void setup() { 91 | Serial.begin(115200); 92 | randomSeed(analogRead(0)); 93 | 94 | setup_wifi(); 95 | 96 | client.setServer(mqtt_server, mqtt_port); 97 | client.setCallback(callback); 98 | } 99 | 100 | void loop() { 101 | 102 | float temperature = random(200, 301) / 10.0; 103 | 104 | int err = reconnect(); 105 | if(err != 0){ 106 | // TODO buffer the measurement to send next time 107 | Serial.println("Could not reconnect: " + String(err)); 108 | } else { 109 | client.loop(); // process incoming messages and maintain connection to server 110 | 111 | // TODO add sequence number 112 | String json = "{\"temperature\":" + String(temperature,1) + "}"; 113 | // Serial.println(json); 114 | client.publish("v1/devices/me/telemetry", json.c_str()); 115 | 116 | } 117 | delay(2000); 118 | } 119 | -------------------------------------------------------------------------------- /09-security/src/02_MQTTS/mosquitto.org.crt: -------------------------------------------------------------------------------- 1 | "-----BEGIN CERTIFICATE-----\n"\ 2 | "MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL\n" \ 3 | "BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG\n" \ 4 | "A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU\n" \ 5 | "BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv\n" \ 6 | "by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE\n" \ 7 | "BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES\n" \ 8 | "MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp\n" \ 9 | "dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ\n" \ 10 | "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg\n" \ 11 | "UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW\n" \ 12 | "Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA\n" \ 13 | "s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH\n" \ 14 | "3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo\n" \ 15 | "E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT\n" \ 16 | "MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV\n" \ 17 | "6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n" \ 18 | "BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC\n" \ 19 | "6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf\n" \ 20 | "+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK\n" \ 21 | "sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839\n" \ 22 | "LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE\n" \ 23 | "m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=\n" \ 24 | "-----END CERTIFICATE-----\n" 25 | -------------------------------------------------------------------------------- /09-security/src/03_OAuth_Device_Flow/ISRGRootX1.pem: -------------------------------------------------------------------------------- 1 | "-----BEGIN CERTIFICATE-----\n" \ 2 | "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \ 3 | "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \ 4 | "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \ 5 | "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \ 6 | "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \ 7 | "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \ 8 | "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \ 9 | "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \ 10 | "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \ 11 | "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \ 12 | "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \ 13 | "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \ 14 | "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \ 15 | "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \ 16 | "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \ 17 | "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \ 18 | "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \ 19 | "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \ 20 | "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \ 21 | "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \ 22 | "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \ 23 | "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \ 24 | "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \ 25 | "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \ 26 | "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \ 27 | "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \ 28 | "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \ 29 | "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \ 30 | "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \ 31 | "-----END CERTIFICATE-----\n" 32 | -------------------------------------------------------------------------------- /09-security/src/old/04_WifiProbing/04_WifiProbing.ino: -------------------------------------------------------------------------------- 1 | // by Ray Burnette 20161013 compiled on Linux 16.3 using Arduino 1.6.12 2 | //Hacked by Kosme 20170520 compiled on Ubuntu 14.04 using Arduino 1.6.11 3 | 4 | #include 5 | #include "./functions.h" 6 | 7 | #define disable 0 8 | #define enable 1 9 | unsigned int channel = 1; 10 | 11 | void setup() { 12 | Serial.begin(57600); 13 | Serial.printf("\n\nSDK version:%s\n\r", system_get_sdk_version()); 14 | Serial.println(F("ESP8266 enhanced sniffer by Kosme https://github.com/kosme")); 15 | 16 | wifi_set_opmode(STATION_MODE); // Promiscuous works only with station mode 17 | wifi_set_channel(channel); 18 | wifi_promiscuous_enable(disable); 19 | wifi_set_promiscuous_rx_cb(promisc_cb); // Set up promiscuous callback 20 | wifi_promiscuous_enable(enable); 21 | } 22 | 23 | void loop() { 24 | channel = 1; 25 | wifi_set_channel(channel); 26 | while (true) { 27 | nothing_new++; // Array is not finite, check bounds and adjust if required 28 | if (nothing_new > 100) { 29 | nothing_new = 0; 30 | channel++; 31 | if (channel == 15) break; // Only scan channels 1 to 14 32 | wifi_set_channel(channel); 33 | } 34 | delay(1); // critical processing timeslice for NONOS SDK! No delay(0) yield() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /09-security/src/old/04_WifiProbing/Notes.h: -------------------------------------------------------------------------------- 1 | // Notes.h tab in Arduino IDE is only for comments and references! 2 | 3 | // based on RandDruid/esp8266-deauth (MIT) https://github.com/RandDruid/esp8266-deauth 4 | // inspired by kripthor/WiFiBeaconJam (no license) https://github.com/kripthor/WiFiBeaconJam 5 | // https://git.schneefux.xyz/schneefux/jimmiejammer/src/master/jimmiejammer.ino 6 | // requires SDK v1.3: install esp8266/Arduino from git and checkout commit 1c5751460b7988041fdc80e0f28a31464cdf97a3 7 | // Modified by M. Ray Burnette for publication as WiFi Sniffer 20161013 8 | // Modified by Kosme for publication 9 | /* 10 | Arduino 1.6.12 on Linux Mint 17.3 11 | Sketch uses 227,309 bytes (21%) of program storage space. Maximum is 1,044,464 bytes. 12 | Global variables use 45,196 bytes (55%) of dynamic memory, leaving 36,724 bytes for local variables. Maximum is 81,920 bytes. 13 | 14 | */ 15 | 16 | /* 17 | // beacon template 18 | uint8_t template_beacon[128] = { 0x80, 0x00, 0x00, 0x00, 19 | /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 20 | /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 21 | /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 22 | /*22*/ 0xc0, 0x6c, 23 | /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, 24 | /*32*/ 0x64, 0x00, 25 | /*34*/ 0x01, 0x04, 26 | /* SSID */ 27 | /*36*/ 0x00, 0x06, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 28 | 0x01, 0x08, 0x82, 0x84, 29 | 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01, 30 | /*56*/ 0x04 31 | }; 32 | * / 33 | 34 | /* Notes: 35 | Ref: http://www.esp8266.com/viewtopic.php?f=32&t=7025 36 | In the ESP8266WiFi.h, there is the function getNetworkInfo() which I presume allows you to get 37 | info for hidden AP. 38 | 39 | bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden); 40 | CODE: SELECT ALL 41 | /** 42 | loads all infos from a scanned wifi in to the ptr parameters 43 | @param networkItem uint8_t 44 | @param ssid const char* 45 | @param encryptionType uint8_t 46 | @param RSSI int32_t 47 | @param BSSID uint8_t * 48 | @param channel int32_t 49 | @param isHidden bool 50 | @return (true if ok) 51 | */ 52 | 53 | /* Serial Console Sample Output: 54 | ESP8266 mini-sniff by Ray Burnette http://www.hackster.io/rayburne/projects 55 | Type: /-------MAC------/-----WiFi Access Point SSID-----/ /----MAC---/ Chnl RSSI 56 | BEACON: <=============== [ TardisTime] 1afe34a08bc9 8 -76 57 | BEACON: <=============== [ xfinitywifi] 56571a0730c0 11 -90 58 | BEACON: <=============== [ ] 52571a0730c0 11 -91 59 | BEACON: <=============== [ ATTGH6Gs22] 1005b1d6ff90 11 -95 60 | BEACON: <=============== [ ATT4P3G9f8] 1c1448777420 11 -92 61 | BEACON: <=============== [ HOME-30C2] 5c571a0730c0 11 -91 62 | BEACON: <=============== [ ATT8Q4z656] b077acc4dfd0 11 -92 63 | BEACON: <=============== [ HOME-B1C2] 94877c55b1c0 11 -94 64 | BEACON: <=============== [ HUXU2012] 0c54a5d6e480 6 -94 65 | BEACON: <=============== [ xfinitywifi] 0c54a5d6e482 6 -97 66 | BEACON: <=============== [ ] 0c54a5d6e481 6 -96 67 | DEVICE: 18fe34fdc2b8 ==> [ TardisTime] 1afe34a08bc9 8 -79 68 | DEVICE: 18fe34f977a0 ==> [ TardisTime] 1afe34a08bc9 8 -94 69 | DEVICE: 6002b4484f2d ==> [ ATTGH6Gs22] 0180c2000000 11 -98 70 | BEACON: <=============== [ HOME-01FC-2.4] 84002da251d8 6 -100 71 | DEVICE: 503955d34834 ==> [ ATT8Q4z656] 01005e7ffffa 11 -87 72 | BEACON: <=============== [ ] 84002da251d9 6 -98 73 | BEACON: <=============== [ xfinitywifi] 84002da251da 6 -95 74 | BEACON: <=============== [ ] fa8fca34e26c 11 -94 75 | DEVICE: cc0dec048363 ==> [ ATT8Q4z656] 01005e7ffffa 11 -88 76 | BEACON: <=============== [ ] fa8fca95bad3 11 -92 77 | BEACON: <=============== [ HOME-5475] 58238c3b5475 1 -96 78 | BEACON: <=============== [ xfinitywifi] 5a238c3b5477 1 -94 79 | BEACON: <=============== [ ] 5a238c3b5476 1 -96 80 | DEVICE: 1859330bf08e ==> [ ATT8Q4z656] 01005e7ffffa 11 -92 81 | BEACON: <=============== [ ] 92877c55b1c0 11 -92 82 | DEVICE: f45fd47bd5e0 ==> [ ATTGH6Gs22] ffffffffffff 11 -93 83 | BEACON: <=============== [ Lynch] 744401480a27 11 -96 84 | BEACON: <=============== [ xfinitywifi] 96877c55b1c0 11 -93 85 | DEVICE: f43e9d006c10 ==> [ xfinitywifi] 8485066ff726 6 -96 86 | DEVICE: 285aeb4f16bf ==> [ ATTGH6Gs22] 3333ffb3c678 11 -94 87 | DEVICE: 006b9e7fab90 ==> [ ATTGH6Gs22] 01005e7ffffa 11 -91 88 | DEVICE: 78456155b9f0 ==> [ Lynch] 01005e7ffffa 11 -95 89 | DEVICE: 6cadf84a419d ==> [ HOME-30C2] 88cb8787697a 11 -89 90 | BEACON: <=============== [ Verizon-SM-G935V-6526] a608ea306526 11 -92 91 | 92 | 93 | */ 94 | -------------------------------------------------------------------------------- /09-security/src/old/04_WifiProbing/functions.h: -------------------------------------------------------------------------------- 1 | // This-->tab == "functions.h" 2 | 3 | // Expose Espressif SDK functionality 4 | extern "C" { 5 | #include "user_interface.h" 6 | typedef void (*freedom_outside_cb_t)(uint8 status); 7 | int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); 8 | void wifi_unregister_send_pkt_freedom_cb(void); 9 | int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq); 10 | } 11 | 12 | #include 13 | #include "./structures.h" 14 | 15 | #define MAX_APS_TRACKED 100 16 | #define MAX_CLIENTS_TRACKED 200 17 | 18 | int aps_known_count = 0; // Number of known APs 19 | int nothing_new = 0; 20 | int clients_known_count = 0; // Number of known CLIENTs 21 | 22 | void promisc_cb(uint8_t *buf, uint16_t len) 23 | { 24 | signed potencia; 25 | if (len == 12) { 26 | struct RxControl *sniffer = (struct RxControl*) buf; 27 | potencia = sniffer->rssi; 28 | } else if (len == 128) { 29 | struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf; 30 | struct beaconinfo beacon = parse_beacon(sniffer->buf, 112, sniffer->rx_ctrl.rssi); 31 | potencia = sniffer->rx_ctrl.rssi; 32 | } else { 33 | struct sniffer_buf *sniffer = (struct sniffer_buf*) buf; 34 | potencia = sniffer->rx_ctrl.rssi; 35 | } 36 | 37 | // Position 12 in the array is where the packet type number is located 38 | // For info on the different packet type numbers check: 39 | // https://stackoverflow.com/questions/12407145/interpreting-frame-control-bytes-in-802-11-wireshark-trace 40 | // https://supportforums.cisco.com/document/52391/80211-frames-starter-guide-learn-wireless-sniffer-traces 41 | // https://ilovewifi.blogspot.mx/2012/07/80211-frame-types.html 42 | if((buf[12]==0x88)||(buf[12]==0x40)||(buf[12]==0x94)||(buf[12]==0xa4)||(buf[12]==0xb4)||(buf[12]==0x08)) 43 | { 44 | Serial.printf("%02x\n",buf[12]); 45 | // if(buf[12]==0x40) Serial.printf("Disconnected: "); 46 | // if(buf[12]==0x08) Serial.printf("Data: "); 47 | // if(buf[12]==0x88) Serial.printf("QOS: "); 48 | // Origin MAC address starts at byte 22 49 | // Print MAC address 50 | for(int i=0;i<5;i++) { 51 | Serial.printf("%02x:",buf[22+i]); 52 | } 53 | Serial.printf("%02x ",buf[22+5]); 54 | // Signal strength is in byte 0 55 | Serial.printf("%i\n",int8_t(buf[0])); 56 | 57 | // Enable this lines if you want to scan for a specific MAC address 58 | // Specify desired MAC address on line 10 of structures.h 59 | /*int same = 1; 60 | for(int i=0;i<6;i++) 61 | { 62 | if(buf[22+i]!=desired[i]) 63 | { 64 | same=0; 65 | break; 66 | } 67 | } 68 | if(same) 69 | { 70 | 71 | } 72 | //different device 73 | else 74 | { 75 | 76 | }*/ 77 | } 78 | //Different packet type numbers 79 | else 80 | { 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /09-security/src/old/04_WifiProbing/structures.h: -------------------------------------------------------------------------------- 1 | // This-->tab == "structures.h" 2 | 3 | #define ETH_MAC_LEN 6 4 | 5 | uint8_t broadcast1[3] = { 0x01, 0x00, 0x5e }; 6 | uint8_t broadcast2[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 7 | uint8_t broadcast3[3] = { 0x33, 0x33, 0x00 }; 8 | 9 | //If you want to detect a specific MAC Addess, put it here. 10 | uint8_t desired[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 11 | 12 | struct beaconinfo 13 | { 14 | uint8_t bssid[ETH_MAC_LEN]; 15 | uint8_t ssid[33]; 16 | int ssid_len; 17 | int channel; 18 | int err; 19 | signed rssi; 20 | uint8_t capa[2]; 21 | }; 22 | 23 | struct clientinfo 24 | { 25 | uint8_t bssid[ETH_MAC_LEN]; 26 | uint8_t station[ETH_MAC_LEN]; 27 | uint8_t ap[ETH_MAC_LEN]; 28 | int channel; 29 | int err; 30 | signed rssi; 31 | uint16_t seq_n; 32 | }; 33 | 34 | /* ============================================== 35 | Promiscous callback structures, see ESP manual 36 | ============================================== */ 37 | struct RxControl { 38 | signed rssi: 8; 39 | unsigned rate: 4; 40 | unsigned is_group: 1; 41 | unsigned: 1; 42 | unsigned sig_mode: 2; 43 | unsigned legacy_length: 12; 44 | unsigned damatch0: 1; 45 | unsigned damatch1: 1; 46 | unsigned bssidmatch0: 1; 47 | unsigned bssidmatch1: 1; 48 | unsigned MCS: 7; 49 | unsigned CWB: 1; 50 | unsigned HT_length: 16; 51 | unsigned Smoothing: 1; 52 | unsigned Not_Sounding: 1; 53 | unsigned: 1; 54 | unsigned Aggregation: 1; 55 | unsigned STBC: 2; 56 | unsigned FEC_CODING: 1; 57 | unsigned SGI: 1; 58 | unsigned rxend_state: 8; 59 | unsigned ampdu_cnt: 8; 60 | unsigned channel: 4; 61 | unsigned: 12; 62 | }; 63 | 64 | struct LenSeq { 65 | uint16_t length; 66 | uint16_t seq; 67 | uint8_t address3[6]; 68 | }; 69 | 70 | struct sniffer_buf { 71 | struct RxControl rx_ctrl; 72 | uint8_t buf[36]; 73 | uint16_t cnt; 74 | struct LenSeq lenseq[1]; 75 | }; 76 | 77 | struct sniffer_buf2 { 78 | struct RxControl rx_ctrl; 79 | uint8_t buf[112]; 80 | uint16_t cnt; 81 | uint16_t len; 82 | }; 83 | 84 | struct clientinfo parse_data(uint8_t *frame, uint16_t framelen, signed rssi, unsigned channel) 85 | { 86 | struct clientinfo ci; 87 | ci.channel = channel; 88 | ci.err = 0; 89 | ci.rssi = rssi; 90 | int pos = 36; 91 | uint8_t *bssid; 92 | uint8_t *station; 93 | uint8_t *ap; 94 | uint8_t ds; 95 | 96 | ds = frame[1] & 3; //Set first 6 bits to 0 97 | switch (ds) { 98 | // p[1] - xxxx xx00 => NoDS p[4]-DST p[10]-SRC p[16]-BSS 99 | case 0: 100 | bssid = frame + 16; 101 | station = frame + 10; 102 | ap = frame + 4; 103 | break; 104 | // p[1] - xxxx xx01 => ToDS p[4]-BSS p[10]-SRC p[16]-DST 105 | case 1: 106 | bssid = frame + 4; 107 | station = frame + 10; 108 | ap = frame + 16; 109 | break; 110 | // p[1] - xxxx xx10 => FromDS p[4]-DST p[10]-BSS p[16]-SRC 111 | case 2: 112 | bssid = frame + 10; 113 | // hack - don't know why it works like this... 114 | if (memcmp(frame + 4, broadcast1, 3) || memcmp(frame + 4, broadcast2, 3) || memcmp(frame + 4, broadcast3, 3)) { 115 | station = frame + 16; 116 | ap = frame + 4; 117 | } else { 118 | station = frame + 4; 119 | ap = frame + 16; 120 | } 121 | break; 122 | // p[1] - xxxx xx11 => WDS p[4]-RCV p[10]-TRM p[16]-DST p[26]-SRC 123 | case 3: 124 | bssid = frame + 10; 125 | station = frame + 4; 126 | ap = frame + 4; 127 | break; 128 | } 129 | 130 | memcpy(ci.station, station, ETH_MAC_LEN); 131 | memcpy(ci.bssid, bssid, ETH_MAC_LEN); 132 | memcpy(ci.ap, ap, ETH_MAC_LEN); 133 | 134 | ci.seq_n = frame[23] * 0xFF + (frame[22] & 0xF0); 135 | return ci; 136 | } 137 | 138 | struct beaconinfo parse_beacon(uint8_t *frame, uint16_t framelen, signed rssi) 139 | { 140 | struct beaconinfo bi; 141 | bi.ssid_len = 0; 142 | bi.channel = 0; 143 | bi.err = 0; 144 | bi.rssi = rssi; 145 | int pos = 36; 146 | 147 | if (frame[pos] == 0x00) { 148 | while (pos < framelen) { 149 | switch (frame[pos]) { 150 | case 0x00: //SSID 151 | bi.ssid_len = (int) frame[pos + 1]; 152 | if (bi.ssid_len == 0) { 153 | memset(bi.ssid, '\x00', 33); 154 | break; 155 | } 156 | if (bi.ssid_len < 0) { 157 | bi.err = -1; 158 | break; 159 | } 160 | if (bi.ssid_len > 32) { 161 | bi.err = -2; 162 | break; 163 | } 164 | memset(bi.ssid, '\x00', 33); 165 | memcpy(bi.ssid, frame + pos + 2, bi.ssid_len); 166 | bi.err = 0; // before was error?? 167 | break; 168 | case 0x03: //Channel 169 | bi.channel = (int) frame[pos + 2]; 170 | pos = -1; 171 | break; 172 | default: 173 | break; 174 | } 175 | if (pos < 0) break; 176 | pos += (int) frame[pos + 1] + 2; 177 | } 178 | } else { 179 | bi.err = -3; 180 | } 181 | 182 | bi.capa[0] = frame[34]; 183 | bi.capa[1] = frame[35]; 184 | memcpy(bi.bssid, frame + 10, ETH_MAC_LEN); 185 | return bi; 186 | } 187 | -------------------------------------------------------------------------------- /10-device-management/Device Management.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/Device Management.pdf -------------------------------------------------------------------------------- /10-device-management/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | ## Measure battery voltage 4 | 5 | ### Measuring analog voltages with ESP 6 | Battery voltage cannot be measured on a digital pin, because it is an analog value that must be converted to digital first. Luckily, [ESP8266](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf) and [ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html) both have a built in ADC (analog to digital converter). 7 | 8 | This exercise can be done with both **ESP8266** and **ESP32**, but you must be aware of the differences. 9 | - **ESP8266** - the chip itself expects a voltage within the range [0,1V], however there is usually a voltage divider on the board (Wemos D1 and NodeMCU), that allows us to pass higher voltages. For example, Wemos D1 has a 1/3.3 divider, that allows us to pass voltages in the range [0,3.3V] 10 | 11 | > [**THE ABSOLUTE MAX TOLERABLE VOLTAGE ON THE RAW ANALOG PIN IS NO MORE THAN 1.8V**](https://www.esp8266.com/viewtopic.php?f=5&t=5556). Applying more will damage the board. Due to this, we may be forgiven if we pass e.g. 5V to the **input of the built in divider**. However, in all cases whe shall aim to have less than 1V on the internal analog pin. 12 | 13 | - **ESP32** - the chip has 2 ADCs that can be assigned to different pins. There is also a built in attenuator 14 | [This video](https://www.youtube.com/watch?v=RlKMJknsNpo) has some useful clarifications on the ESP32 ADC peculiarities. 15 | 16 | ### Voltage dividers 17 | If you need to measure higher voltages, you have to use e.g. a voltage divider to bring down the voltage to the allowed values. 18 | 19 | ![Voltage divider](divider_simulation.png "Voltage divider") 20 | > [Live divider](https://crcit.net/c/9a0ef05f) 21 | 22 | This however may be in conflict with the board's built in divider and as a result you may get wrong values. Always check the cirquit diagram of the board before you design a divider cirquit and then use a cirquit simulator (e.g. [QUCS](http://qucs.sourceforge.net/)) to simulate it and double check that you don't exceed the voltages and that your assumptions are correct. 23 | 24 | ### Measuring Vcc supply voltage 25 | The ESP8266 ADC can be configured to [measure the Vcc supply voltate](https://arduino-esp8266.readthedocs.io/en/latest/reference.html#analog-input) 26 | 27 | ## OTA update 28 | use `Sketch > Export Compiled Binary` menu item to obtain the `bin` file. More details in [this tutorial](https://randomnerdtutorials.com/bin-binary-files-sketch-arduino-ide/). 29 | 30 | ### ESP8266 31 | * [Local HTTP server + browser update](https://github.com/esp8266/Arduino/tree/2.3.0/doc/ota_updates#web-browser) - 32 | * [Remote HTTP server update](https://github.com/esp8266/Arduino/tree/2.3.0/doc/ota_updates#http-server) - use a local XAMPP server and get the PHP example running and adapted to your use case. 33 | 34 | ### ESP32 35 | Use the [official ESP32 library for OTA](https://github.com/espressif/arduino-esp32/tree/master/libraries/Update). They also have an useful [example how to update from S3](https://github.com/espressif/arduino-esp32/blob/master/libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino). 36 | 37 | 38 | 39 | ## Onboarding 40 | Implement onboarding with WifiManager. There are different libraries, some of which work only on ESP8266. 41 | * [ESP8266 WiFiManager](https://github.com/tzapu/WiFiManager) 42 | * [ESP32&ESP8266 WifiManager](https://github.com/zhouhan0126/WIFIMANAGER-ESP32) 43 | * [ESP32 only](https://github.com/tonyp7/esp32-wifi-manager) 44 | * [IotWebConf](https://github.com/prampec/IotWebConf) 45 | 46 | Goals: 47 | * Use shall be able to enter WiFi credentials of a brand new device 48 | * When the wifi connection is lost, user shall be able to re-enter credentials or connect to a different network 49 | 50 | ## Detect unexpected restarts (e.g. WDT) 51 | ### ESP8266 52 | * Use the ESP8266 SDK to read the [reason for reset](https://www.espressif.com/sites/default/files/documentation/esp8266_reset_causes_and_common_fatal_exception_causes_en.pdf). 53 | * Look around for other interesting information [in the API](https://github.com/esp8266/Arduino/blob/61cd8d83859524db0066a647de3de3f6a0039bb2/libraries/esp8266/examples/TestEspApi/TestEspApi.ino) 54 | 55 | ### ESP32 56 | Take a look at the [official example for reset reason](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/ResetReason/ResetReason.ino). Take into account that there are two CPUs in ESP32. 57 | 58 | 59 | # References 60 | * [Resistor color codes](https://www.digikey.com/en/resources/conversion-calculators/conversion-calculator-resistor-color-code-5-band) 61 | * [Arduino timekeeping](http://www.instructables.com/id/TESTED-Timekeeping-on-ESP8266-Arduino-Uno-WITHOUT-/) 62 | * [Hotspot manager for Android](https://play.google.com/store/apps/details?id=com.etustudio.android.hotspotmanager&hl=en) 63 | * [Multicast DNS](https://en.wikipedia.org/wiki/Multicast_DNS) 64 | * [DNS-SD](http://www.dns-sd.org/) 65 | 66 | # Extra 67 | * [ESPHome & HomeAssistant for home automation](https://esphome.io/guides/getting_started_hassio.html) 68 | -------------------------------------------------------------------------------- /10-device-management/divider_simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/divider_simulation.png -------------------------------------------------------------------------------- /10-device-management/src/01_AnalogVoltageMeasurement/01_AnalogVoltageMeasurement.ino: -------------------------------------------------------------------------------- 1 | unsigned int raw=0; 2 | float volt=0.0; 3 | const int sleepTimeS = 60; 4 | 5 | const int resistor = 100; 6 | const float scalingFactor = 5.14; // TODO how was this calculated? 7 | 8 | 9 | void setup() { 10 | 11 | Serial.begin(115200); 12 | Serial.println("Serial is up"); 13 | } 14 | 15 | void loop() { 16 | 17 | pinMode(A0, INPUT); 18 | raw = analogRead(A0); 19 | 20 | volt=raw/1023.0; 21 | volt=volt*scalingFactor; 22 | 23 | Serial.println("Voltage: " + String(volt) + " raw:" + String(raw)); 24 | delay(1000); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /10-device-management/src/02_WebUpdater/02_WebUpdater.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Forked from the official ESP8266 examples 3 | To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266.local/update 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | const char* host = "esp8266"; // shall be accessible at http://esp8266.local 13 | const char* ssid = "AndroidAP"; 14 | const char* password = "*******"; 15 | 16 | ESP8266WebServer httpServer(80); 17 | ESP8266HTTPUpdateServer httpUpdater; 18 | 19 | void setup(void){ 20 | 21 | Serial.begin(115200); 22 | WiFi.mode(WIFI_AP_STA); 23 | WiFi.begin(ssid, password); 24 | 25 | while(WiFi.waitForConnectResult() != WL_CONNECTED){ 26 | WiFi.begin(ssid, password); 27 | Serial.println("WiFi failed, retrying."); 28 | } 29 | 30 | MDNS.begin(host); // used to advertise the host through mDNS 31 | 32 | httpUpdater.setup(&httpServer); 33 | httpServer.begin(); 34 | 35 | MDNS.addService("http", "tcp", 80); // advertise the service on DNS-SD 36 | Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host); 37 | } 38 | 39 | void loop(void){ 40 | httpServer.handleClient(); // non blocking 41 | // do other useful stuff here 42 | 43 | } 44 | -------------------------------------------------------------------------------- /10-device-management/src/03_WiFiManager_simple/03_WiFiManager_simple.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | #include 8 | 9 | void setup() { 10 | // put your setup code here, to run once: 11 | Serial.begin(115200); 12 | 13 | //WiFiManager 14 | //Local intialization. Once its business is done, there is no need to keep it around 15 | WiFiManager wifiManager; 16 | //reset saved settings 17 | //wifiManager.resetSettings(); 18 | 19 | //set custom ip for portal 20 | //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 21 | 22 | //fetches ssid and pass from eeprom and tries to connect 23 | //if it does not connect it starts an access point with the specified name 24 | //here "AutoConnectAP" 25 | //and goes into a blocking loop awaiting configuration 26 | wifiManager.autoConnect("AutoConnectAP"); 27 | //or use this for auto generated name ESP + ChipID 28 | //wifiManager.autoConnect(); 29 | 30 | 31 | //if you get here you have connected to the WiFi 32 | Serial.println("connected...yeey :)"); 33 | 34 | } 35 | 36 | void loop() { 37 | // your code here ... 38 | 39 | } 40 | -------------------------------------------------------------------------------- /10-device-management/src/04_WiFiManager_httpserver/04_WiFiManager_httpserver.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | #include 8 | 9 | ESP8266WebServer server(80); 10 | 11 | const int led = 13; 12 | 13 | void handleRoot() { 14 | digitalWrite(led, 1); 15 | server.send(200, "text/plain", "hello from esp8266!"); 16 | digitalWrite(led, 0); 17 | } 18 | 19 | void handleNotFound(){ 20 | digitalWrite(led, 1); 21 | String message = "File Not Found\n\n"; 22 | message += "URI: "; 23 | message += server.uri(); 24 | message += "\nMethod: "; 25 | message += (server.method() == HTTP_GET)?"GET":"POST"; 26 | message += "\nArguments: "; 27 | message += server.args(); 28 | message += "\n"; 29 | for (uint8_t i=0; ireason) + " exccause: " + String(rtc_info->exccause)); 15 | #endif 16 | } 17 | 18 | void loop() { 19 | Serial.println("Inside loop"); 20 | delay(1000); 21 | while(true){}; 22 | } 23 | -------------------------------------------------------------------------------- /10-device-management/src/06_WiFiProvisioner/WiFiProvisioner_simple.ino: -------------------------------------------------------------------------------- 1 | /* 2 | WiFi Provisioning Example 3 | ===================================== 4 | This code demonstrates how to use the WiFiProvisioner library to configure 5 | WiFi credentials for an ESP32 device. The WiFiProvisioner library allows 6 | users to set up WiFi credentials dynamically, making it easier to connect 7 | the device to a network without hardcoding SSID and password. 8 | 9 | Key Features: 10 | - Dynamically configure WiFi credentials using a provisioning interface. 11 | - Hide additional input fields (e.g., reset or custom fields) for simplicity. 12 | - Provide a callback function to handle successful provisioning. 13 | 14 | How It Works: 15 | 1. The `WiFiProvisioner` instance is created and configured. 16 | 2. Additional input fields (e.g., reset or custom fields) are disabled for simplicity. 17 | 3. A success callback is defined to handle the event when WiFi credentials are successfully provisioned. 18 | 4. The provisioning process is started, allowing the user to input WiFi credentials. 19 | 5. Once provisioning is complete, the device connects to the specified WiFi network. 20 | */ 21 | 22 | #include 23 | 24 | void setup() { 25 | Serial.begin(9600); 26 | 27 | // Create the WiFiProvisioner instance 28 | WiFiProvisioner provisioner; 29 | 30 | // Configure to hide additional fields 31 | provisioner.getConfig().SHOW_INPUT_FIELD = false; // No additional input field 32 | provisioner.getConfig().SHOW_RESET_FIELD = false; // No reset field 33 | 34 | // Set the success callback 35 | provisioner.onSuccess( 36 | [](const char *ssid, const char *password, const char *input) { 37 | Serial.printf("Provisioning successful! Connected to SSID: %s\n", ssid); 38 | if (password) { 39 | Serial.printf("Password: %s\n", password); 40 | } 41 | }); 42 | 43 | // Start provisioning 44 | provisioner.startProvisioning(); 45 | } 46 | 47 | void loop() { delay(100); } 48 | -------------------------------------------------------------------------------- /10-device-management/src/06_WiFiProvisioner/WiFiProvisioner_simple.md: -------------------------------------------------------------------------------- 1 | 2 | # *WiFiProvisioner library* 3 | 4 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 5 | 6 | You already have some components to use: 7 | 8 | - **[ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf)**. 9 | 10 | ![alt text](/04-displays-and-actuators/src/servo/images/esp32.png) 11 | 12 | ## Schematic and connections 13 | 14 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 15 | 16 | ## Code to Run (Arduino Sketches) 17 | 18 | 1. **Install the WiFiProvisioner library** 19 | 20 | - Go to Sketch > Include Library > Manage Libraries… 21 | - Search for WiFiProvisioner. 22 | - Install the library. 23 | ![alt text](images/wifiprov.png) 24 | 25 | 2. **Run this sketch in Arduino IDE**, This code demonstrates how to use the WiFiProvisioner library to configure WiFi credentials for an ESP32 device. The WiFiProvisioner library allows 26 | users to set up WiFi credentials dynamically, making it easier to connect 27 | the device to a network without hardcoding SSID and password. 28 | - 1.Search for WiFi SSID starting with "ESP32 Wi-Fi Provisioniong" and connect to it. It is not providing any internet, but connectivity to the ESP32. 29 | - 2.Open 192.168.4.1 and see the available WiFi SSIDs. 30 | - 3.Select the SSID 31 | - 4.Enter a WiFi password. 32 | 33 | ![alt text](images/wifiprov_init.png) 34 | 35 | ```cpp 36 | /* 37 | WiFi Provisioning Example 38 | ===================================== 39 | This code demonstrates how to use the WiFiProvisioner library to configure 40 | WiFi credentials for an ESP32 device. The WiFiProvisioner library allows 41 | users to set up WiFi credentials dynamically, making it easier to connect 42 | the device to a network without hardcoding SSID and password. 43 | 44 | Key Features: 45 | - Dynamically configure WiFi credentials using a provisioning interface. 46 | - Hide additional input fields (e.g., reset or custom fields) for simplicity. 47 | - Provide a callback function to handle successful provisioning. 48 | 49 | How It Works: 50 | 1. The `WiFiProvisioner` instance is created and configured. 51 | 2. Additional input fields (e.g., reset or custom fields) are disabled for simplicity. 52 | 3. A success callback is defined to handle the event when WiFi credentials are successfully provisioned. 53 | 4. The provisioning process is started, allowing the user to input WiFi credentials. 54 | 5. Once provisioning is complete, the device connects to the specified WiFi network. 55 | */ 56 | 57 | #include 58 | 59 | void setup() { 60 | Serial.begin(9600); 61 | 62 | // Create the WiFiProvisioner instance 63 | WiFiProvisioner provisioner; 64 | 65 | // Configure to hide additional fields 66 | provisioner.getConfig().SHOW_INPUT_FIELD = false; // No additional input field 67 | provisioner.getConfig().SHOW_RESET_FIELD = false; // No reset field 68 | 69 | // Set the success callback 70 | provisioner.onSuccess( 71 | [](const char *ssid, const char *password, const char *input) { 72 | Serial.printf("Provisioning successful! Connected to SSID: %s\n", ssid); 73 | if (password) { 74 | Serial.printf("Password: %s\n", password); 75 | } 76 | }); 77 | 78 | // Start provisioning 79 | provisioner.startProvisioning(); 80 | } 81 | 82 | void loop() { delay(100); } 83 | 84 | ``` 85 | -------------------------------------------------------------------------------- /10-device-management/src/06_WiFiProvisioner/images/wifiprov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/06_WiFiProvisioner/images/wifiprov.png -------------------------------------------------------------------------------- /10-device-management/src/06_WiFiProvisioner/images/wifiprov_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/06_WiFiProvisioner/images/wifiprov_init.png -------------------------------------------------------------------------------- /10-device-management/src/07_core_temperature/core_temperature.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Core Temperature Measurement Example 3 | ===================================== 4 | This code demonstrates how to measure the CPU core temperature of an ESP32. 5 | The `temperatureRead()` function is used to retrieve the internal temperature 6 | of the ESP32 chip. The temperature is printed to the Serial Monitor. 7 | More details about the `temperatureRead()` function: 8 | 9 | Purpose: 10 | The temperatureRead() function reads the internal temperature sensor of the ESP32 chip and returns the temperature in degrees Celsius. 11 | 12 | Declaration: 13 | The temperatureRead() function is declared in the ESP32 Arduino core library. It is part of the ESP32's hardware abstraction layer (HAL) and is implemented in the ESP-IDF (Espressif IoT Development Framework). 14 | 15 | Return Value: 16 | The function returns a float value representing the temperature in degrees Celsius. 17 | 18 | Usage: 19 | The function does not require any arguments and can be called directly in the code. 20 | 21 | Accuracy: 22 | The temperature value is approximate and may vary depending on the ESP32 model and environmental conditions. It is primarily intended for internal monitoring and not for precise temperature measurement. 23 | 24 | 25 | 26 | Note: 27 | - The temperature value is approximate and may vary depending on the ESP32 model. 28 | - This feature is primarily for internal monitoring and not for precise temperature measurement. 29 | - The temperature is reported in degrees Celsius. 30 | */ 31 | 32 | void setup() { 33 | // Initialize Serial communication 34 | Serial.begin(115200); 35 | delay(1000); // Allow time for the Serial Monitor to initialize 36 | 37 | Serial.println("ESP32 Core Temperature Measurement"); 38 | } 39 | 40 | void loop() { 41 | // Read the CPU core temperature 42 | float temperature = temperatureRead(); 43 | 44 | // Print the temperature to the Serial Monitor 45 | Serial.print("CPU Temperature: "); 46 | Serial.print(temperature); 47 | Serial.println(" °C"); 48 | 49 | // Wait for 1 second before the next reading 50 | delay(1000); 51 | } -------------------------------------------------------------------------------- /10-device-management/src/07_core_temperature/core_temperature.md: -------------------------------------------------------------------------------- 1 | 2 | # *ESP32 Core Temperature Measurement* 3 | 4 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 5 | 6 | You already have some components to use: 7 | 8 | - **[ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf)**. 9 | 10 | ![alt text](/04-displays-and-actuators/src/servo/images/esp32.png) 11 | 12 | ## Schematic and connections 13 | 14 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 15 | 16 | ## Code to Run (Arduino Sketches) 17 | 18 | 1. **No need to install any library** 19 | 20 | 21 | 2. **Run this sketch in Arduino IDE**, The `temperatureRead()` function is used to retrieve the internal temperature 22 | of the ESP32 chip. The temperature is printed to the Serial Monitor in degrees Celsius. 23 | 24 | CPU Temperature: 55.00 °C 25 | CPU Temperature: 55.00 °C. 26 | 27 | ```cpp 28 | /* 29 | Core Temperature Measurement Example 30 | ===================================== 31 | This code demonstrates how to measure the CPU core temperature of an ESP32. 32 | The `temperatureRead()` function is used to retrieve the internal temperature 33 | of the ESP32 chip. The temperature is printed to the Serial Monitor. 34 | More details about the `temperatureRead()` function: 35 | 36 | Purpose: 37 | The temperatureRead() function reads the internal temperature sensor of the ESP32 chip and returns the temperature in degrees Celsius. 38 | 39 | Declaration: 40 | The temperatureRead() function is declared in the ESP32 Arduino core library. It is part of the ESP32's hardware abstraction layer (HAL) and is implemented in the ESP-IDF (Espressif IoT Development Framework). 41 | 42 | Return Value: 43 | The function returns a float value representing the temperature in degrees Celsius. 44 | 45 | Usage: 46 | The function does not require any arguments and can be called directly in the code. 47 | 48 | Accuracy: 49 | The temperature value is approximate and may vary depending on the ESP32 model and environmental conditions. It is primarily intended for internal monitoring and not for precise temperature measurement. 50 | 51 | 52 | 53 | Note: 54 | - The temperature value is approximate and may vary depending on the ESP32 model. 55 | - This feature is primarily for internal monitoring and not for precise temperature measurement. 56 | - The temperature is reported in degrees Celsius. 57 | */ 58 | 59 | void setup() { 60 | // Initialize Serial communication 61 | Serial.begin(115200); 62 | delay(1000); // Allow time for the Serial Monitor to initialize 63 | 64 | Serial.println("ESP32 Core Temperature Measurement"); 65 | } 66 | 67 | void loop() { 68 | // Read the CPU core temperature 69 | float temperature = temperatureRead(); 70 | 71 | // Print the temperature to the Serial Monitor 72 | Serial.print("CPU Temperature: "); 73 | Serial.print(temperature); 74 | Serial.println(" °C"); 75 | 76 | // Wait for 1 second before the next reading 77 | delay(1000); 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /10-device-management/src/08_supply_voltage_measurement/supply_voltage_measurement.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ESP32 USB Voltage Measurement Example (OLIMEX ESP32-DevKit-LiPo) 3 | ======================================================== 4 | This code demonstrates how to measure the USB voltage powering the ESP32 5 | using the internal ADC. Ensure the correct ADC pin and voltage divider ratio 6 | are used based on the board's documentation. 7 | 8 | Some ESP32 boards have an internal voltage divider connected to the VCC pin, which scales down the supply voltage to a range measurable by the ADC (0–3.3V). 9 | The VOLTAGE_DIVIDER_RATIO is used to calculate the actual supply voltage from the measured voltage. For example, if the divider ratio is 2:1, the VOLTAGE_DIVIDER_RATIO is 2.0. 10 | ADC Configuration: 11 | 12 | The ADC pin (e.g., GPIO 35) is used to read the scaled-down voltage. 13 | The ESP32's ADC has a resolution of 12 bits, meaning the raw ADC value ranges from 0 to 4095. 14 | Voltage Calculation: 15 | 16 | The raw ADC value is converted to a voltage using the formula: 17 | Supply Voltage Calculation: 18 | 19 | The supply voltage is calculated using the voltage divider ratio: 20 | Supply Voltage = Measured Voltage * Voltage Divider Ratio 21 | */ 22 | 23 | const int ADC_PIN = 0; // Update this to the correct ADC pin 24 | const float ADC_RESOLUTION = 4095.0; // 12-bit ADC resolution 25 | const float ADC_REF_VOLTAGE = 3.3; // Reference voltage for the ADC (in volts) 26 | const float VOLTAGE_DIVIDER_RATIO = 1.515; // Update this based on the board's documentation 27 | 28 | void setup() { 29 | Serial.begin(115200); 30 | delay(1000); 31 | 32 | Serial.println("ESP32 USB Voltage Measurement"); 33 | } 34 | 35 | void loop() { 36 | int rawADC = analogRead(ADC_PIN); // Read raw ADC value 37 | float measuredVoltage = (rawADC / ADC_RESOLUTION) * ADC_REF_VOLTAGE; // Convert to voltage 38 | float supplyVoltage = measuredVoltage * VOLTAGE_DIVIDER_RATIO; // Calculate supply voltage 39 | 40 | // Debugging output 41 | Serial.print("Raw ADC Value: "); 42 | Serial.println(rawADC); 43 | Serial.print("Measured Voltage: "); 44 | Serial.print(measuredVoltage); 45 | Serial.println(" V"); 46 | Serial.print("Supply Voltage: "); 47 | Serial.print(supplyVoltage); 48 | Serial.println(" V"); 49 | 50 | delay(1000); 51 | } -------------------------------------------------------------------------------- /10-device-management/src/08_supply_voltage_measurement/supply_voltage_measurement.md: -------------------------------------------------------------------------------- 1 | 2 | # *ESP32 USB Voltage Measurement Example* 3 | 4 | We are using Olimex [ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf) 5 | 6 | You already have some components to use: 7 | 8 | - **[ESP32-DevKit-LiPo Board](https://github.com/OLIMEX/ESP32-DevKit-LiPo/blob/master/DOCS/ESP32-DevKit-LiPo-user-manual.pdf)**. 9 | 10 | ![alt text](/04-displays-and-actuators/src/servo/images/esp32.png) 11 | 12 | ## Schematic and connections 13 | 14 | - Pinout of the ESP32 board is shown [here](images/olimex_esp32.png). 15 | 16 | ## Code to Run (Arduino Sketches) 17 | 18 | 1. **No need to install any library** 19 | 20 | 2. **Run this sketch in Arduino IDE**: 21 | Expected Output: The supply voltage will be printed to the Serial Monitor in volts. 22 | Example output: 23 | 24 | ``` 25 | Raw ADC Value: 4095 26 | Measured Voltage: 3.30 V 27 | Supply Voltage: 5.00 V 28 | ``` 29 | 30 | ```cpp 31 | /* 32 | ESP32 USB Voltage Measurement Example (OLIMEX ESP32-DevKit-LiPo) 33 | ======================================================== 34 | This code demonstrates how to measure the USB voltage powering the ESP32 35 | using the internal ADC. Ensure the correct ADC pin and voltage divider ratio 36 | are used based on the board's documentation. 37 | 38 | 39 | **NOTE: AVOID EXCEEDING ADC VOLTAGE LIMITS:** 40 | THE ESP32'S ADC CAN ONLY MEASURE VOLTAGES IN THE RANGE OF 0–3.3V. ENSURE THAT THE VOLTAGE BEING MEASURED IS WITHIN THIS RANGE. 41 | IF THE USB VOLTAGE (5V) IS DIRECTLY CONNECTED TO THE ADC PIN WITHOUT A PROPER VOLTAGE DIVIDER, IT CAN DAMAGE THE ESP32. 42 | 43 | 44 | 1. Internal Voltage Divider: 45 | - Some ESP32 boards have an internal voltage divider connected to the VCC pin, which scales down the supply voltage to a range measurable by the ADC (0–3.3V). 46 | - The VOLTAGE_DIVIDER_RATIO is used to calculate the actual supply voltage from the measured voltage. For example, if the divider ratio is 2:1, the VOLTAGE_DIVIDER_RATIO is 2.0. 47 | 48 | 2. ADC Configuration: 49 | - The ADC pin (e.g., GPIO 35) is used to read the scaled-down voltage. 50 | - The ESP32's ADC has a resolution of 12 bits, meaning the raw ADC value ranges from 0 to 4095. 51 | 52 | 3. Voltage Calculation: 53 | - The raw ADC value is converted to a voltage using the formula: 54 | * Measured Voltage = (Raw ADC Value / ADC Resolution) * Reference Voltage 55 | 56 | 4. Supply Voltage Calculation: 57 | - The supply voltage is calculated using the voltage divider ratio: 58 | * Supply Voltage = Measured Voltage * Voltage Divider Ratio 59 | */ 60 | 61 | const int ADC_PIN = 0; // Update this to the correct ADC pin 62 | const float ADC_RESOLUTION = 4095.0; // 12-bit ADC resolution 63 | const float ADC_REF_VOLTAGE = 3.3; // Reference voltage for the ADC (in volts) 64 | const float VOLTAGE_DIVIDER_RATIO = 1.515; // Update this based on the board's documentation 65 | 66 | void setup() { 67 | Serial.begin(115200); 68 | delay(1000); 69 | 70 | Serial.println("ESP32 USB Voltage Measurement"); 71 | } 72 | 73 | void loop() { 74 | int rawADC = analogRead(ADC_PIN); // Read raw ADC value 75 | float measuredVoltage = (rawADC / ADC_RESOLUTION) * ADC_REF_VOLTAGE; // Convert to voltage 76 | float supplyVoltage = measuredVoltage * VOLTAGE_DIVIDER_RATIO; // Calculate supply voltage 77 | 78 | // Debugging output 79 | Serial.print("Raw ADC Value: "); 80 | Serial.println(rawADC); 81 | Serial.print("Measured Voltage: "); 82 | Serial.print(measuredVoltage); 83 | Serial.println(" V"); 84 | Serial.print("Supply Voltage: "); 85 | Serial.print(supplyVoltage); 86 | Serial.println(" V"); 87 | 88 | delay(1000); 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /10-device-management/src/09_OTA_server/images/export_scetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/09_OTA_server/images/export_scetch.png -------------------------------------------------------------------------------- /10-device-management/src/09_OTA_server/images/ota_update_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/09_OTA_server/images/ota_update_file.png -------------------------------------------------------------------------------- /10-device-management/src/09_OTA_server/images/show_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/09_OTA_server/images/show_folder.png -------------------------------------------------------------------------------- /10-device-management/src/09_OTA_server/images/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/src/09_OTA_server/images/update.png -------------------------------------------------------------------------------- /10-device-management/src/09_OTA_server/ota_server.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ESP32 OTA Server Example 3 | ========================= 4 | This code demonstrates how to set up an OTA server on the ESP32. 5 | It creates a web server that allows you to upload new firmware to the ESP32 6 | via a web interface. 7 | 8 | Steps: 9 | 1. Connect the ESP32 to a WiFi network. 10 | 2. Access the OTA web interface via the ESP32's IP address. 11 | 3. Upload the new firmware file (.bin) through the web interface. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // Replace with your network credentials 19 | const char* ssid = "your SSID"; 20 | const char* password = "your SSID password"; 21 | 22 | // Create a web server on port 80 23 | WebServer server(80); 24 | 25 | // HTML page for the OTA update interface 26 | const char* updatePage = R"rawliteral( 27 | 28 | 29 | 30 | ESP32 OTA Update 31 | 32 | 33 |

ESP32 OTA Update

34 |
35 | 36 | 37 |
38 | 39 | 40 | )rawliteral"; 41 | 42 | // Handle the root URL 43 | void handleRoot() { 44 | server.send(200, "text/html", updatePage); 45 | } 46 | 47 | // Handle the firmware upload 48 | void handleUpdate() { 49 | HTTPUpload& upload = server.upload(); 50 | 51 | if (upload.status == UPLOAD_FILE_START) { 52 | Serial.printf("Update Start: %s\n", upload.filename.c_str()); 53 | if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { 54 | Update.printError(Serial); 55 | return; 56 | } 57 | } else if (upload.status == UPLOAD_FILE_WRITE) { 58 | if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { 59 | Update.printError(Serial); 60 | } 61 | } else if (upload.status == UPLOAD_FILE_END) { 62 | if (Update.end(true)) { 63 | Serial.printf("Update Success: %u bytes\n", upload.totalSize); 64 | } else { 65 | Update.printError(Serial); 66 | } 67 | } 68 | } 69 | 70 | // Handle the update result 71 | void handleUpdateResult() { 72 | if (Update.hasError()) { 73 | server.send(200, "text/plain", "Update Failed"); 74 | } else { 75 | server.send(200, "text/plain", "Update Successful. Rebooting..."); 76 | delay(1000); 77 | ESP.restart(); 78 | } 79 | } 80 | 81 | void setup() { 82 | // Start Serial communication 83 | Serial.begin(115200); 84 | delay(1000); 85 | 86 | // Connect to WiFi 87 | WiFi.begin(ssid, password); 88 | Serial.println("Connecting to WiFi..."); 89 | while (WiFi.status() != WL_CONNECTED) { 90 | delay(500); 91 | Serial.print("."); 92 | } 93 | Serial.println("\nWiFi connected."); 94 | Serial.print("IP Address: "); 95 | Serial.println(WiFi.localIP()); 96 | 97 | // Configure web server routes 98 | server.on("/", HTTP_GET, handleRoot); 99 | server.on("/update", HTTP_POST, handleUpdateResult, handleUpdate); 100 | 101 | // Start the web server 102 | server.begin(); 103 | Serial.println("OTA Server started."); 104 | } 105 | 106 | void loop() { 107 | // Handle client requests 108 | server.handleClient(); 109 | delay(5); 110 | } -------------------------------------------------------------------------------- /10-device-management/thinx-firmware-esp8266-ino.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/10-device-management/thinx-firmware-esp8266-ino.zip -------------------------------------------------------------------------------- /11-data-management-and-analytics/Data Management & Analytics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/11-data-management-and-analytics/Data Management & Analytics.pdf -------------------------------------------------------------------------------- /11-data-management-and-analytics/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 1. [Parquet data format](notebooks/Parquet.ipynb) 3 | 2. [Manipulate and analyze timeseries with Pandas](notebooks/Pandas_timeseries.ipynb) 4 | 3. [Seaborn visualizations](notebooks/TimeSeriesVisualization.ipynb) 5 | 6 | # Extra materials 7 | 8 | - Publications 9 | - [Brandon Rhodes - Pandas From The Ground Up - PyCon 2015](https://www.youtube.com/watch?v=5JnMutdy6Fw) 10 | - [Modern Time Series Analysis | SciPy 2019 Tutorial | Aileen Nielsen](https://www.youtube.com/watch?v=v5ijNXvlC5A) 11 | - [Why Are Time Series Special? : Time Series Talk](https://www.youtube.com/watch?v=ZoJ2OctrFLA&list=PLvcbYUQ5t0UHOLnBzl46_Q6QKtFgfMGc3&index=7) 12 | - [Deep Learning for Time Series | Dimitry Larko | Kaggle Days](https://www.youtube.com/watch?v=svNwWSgz2NM) 13 | - [(Advanced) Neural Controlled Differential Equations for Irregular Time Series](https://arxiv.org/abs/2005.08926) 14 | - Analysis tools 15 | - [Kats tool for time series analysis by facebook research](https://facebookresearch.github.io/Kats/) 16 | - [tsfresh tool for feature extraction](https://github.com/blue-yonder/tsfresh) 17 | - [sktime - A Unified Toolbox for ML with Time Series - Markus Löning | PyData Global 2021](https://www.youtube.com/watch?v=ODspi8-uWgo) 18 | - [Neural Prophet – A powerful AI framework for Time Series Models | PyData Global 2021](https://www.youtube.com/watch?v=S6Qv2ZLQL5o) 19 | - Visualization 20 | - [Seaborn](https://seaborn.pydata.org/) 21 | - [Plotly time series axes](https://plotly.com/python/time-series/) 22 | - Infrastructure tools 23 | - [Parquet article](https://blog.openbridge.com/how-to-be-a-hero-with-powerful-parquet-google-and-amazon-f2ae0f35ee04) 24 | - [Prometheus](https://prometheus.io/docs/) 25 | - [Grafana](https://grafana.com/docs/grafana/latest/) 26 | - [Kafka](https://kafka.apache.org/) 27 | - https://arrow.apache.org/ 28 | -------------------------------------------------------------------------------- /11-data-management-and-analytics/notebooks/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "notebooks" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["pgenevski "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.09" 10 | pandas = "^2.2.2" 11 | numpy = "^1.26.4" 12 | seaborn = "^0.13.2" 13 | matplotlib = "^3.8.4" 14 | dask = {extras = ["complete"], version = "^2024.5.0"} 15 | pyarrow = "^16.0.0" 16 | jupyter = "^1.0.0" 17 | 18 | 19 | [build-system] 20 | requires = ["poetry-core"] 21 | build-backend = "poetry.core.masonry.api" 22 | -------------------------------------------------------------------------------- /15-whats-new-in-iot/Blockchain.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/15-whats-new-in-iot/Blockchain.pdf -------------------------------------------------------------------------------- /15-whats-new-in-iot/PowerManagementAndExistingTech.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/15-whats-new-in-iot/PowerManagementAndExistingTech.pdf -------------------------------------------------------------------------------- /15-whats-new-in-iot/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | No exercises planned for this day. 4 | -------------------------------------------------------------------------------- /15-whats-new-in-iot/WiFi_sensing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/15-whats-new-in-iot/WiFi_sensing.pdf -------------------------------------------------------------------------------- /15-whats-new-in-iot/energy-harvesting-IoT-su.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/15-whats-new-in-iot/energy-harvesting-IoT-su.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Курс Internet of Things (IoT) 2 | 3 | Лекциите и упражненията по темите се провеждат в един ден. Материалите за всяка лекция/упражнение са в съответната папка. 4 | 5 | # Лектори 6 | 7 | | Име | Facebook | LinkedIn | 8 | |----|---|---| 9 | |Павел Геневски | | https://www.linkedin.com/in/pavel-genevski-bb075612/ | 10 | |Николай Китанов | https://www.facebook.com/nikolay.kitanov.5/ | https://www.linkedin.com/in/nikolay-kitanov/ | 11 | |Ивайло Димов | | https://www.linkedin.com/in/ivaylo-dimov-8214a1a9/ | 12 | |Велизар Стоянов | | https://www.linkedin.com/in/velizar-stoyanov-40a7a41b9 | 13 | # Хардуерни компоненти 14 | За курсовия проект е осигурен набор от хардуерни компоненти. 15 | 16 | # Учебен план 17 | 18 | 19 | | Дата | Тема | Лектори | Видео | 20 | | -------------|:-------------------------------------| -----------------:|:-----:| 21 | | 20.02.2025 | Intro to IoT | Павел, Николай | | 22 | | 27.02.2025 | Hardware platforms / ESP | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/JuP9YB0plFs) | 23 | | 06.03.2025 | Sensors | Павел,Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/7YJqtn6doas) | 24 | | 13.03.2025 | Displays and actuators | Павел,Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/6l79UTjuuwg) | 25 | | 20.03.2025 | Practice & Exercises | Павел,Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/6ZNgmo3pdXg) | 26 | | 27.03.2025 | Connectivity 1 | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/cq97WpIIubA) | 27 | | 03.04.2025 | Power management, batteries (Remote) | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/osHbqO7c6O8) | 28 | | 10.04.2025 | Connectivity 2 | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/CGN9f2PfI8I) | 29 | | 17.04.2025 | Vacation | | | 30 | | 24.04.2025 | Security | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/bqQLUAwN6sw) | 31 | | 01.05.2025 | Vacation | Павел, Николай | | 32 | | 08.05.2025 | Device management | | [![Video](images/iot-on-youtube.png)](https://youtu.be/WwzskAgpshQ) | 33 | | 15.05.2025 | Data management and analytics | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/vVaOwJxaxiE) | 34 | | 22.05.2025 | Data management - Exercise | Павел, Николай | [![Video](images/iot-on-youtube.png)](https://youtu.be/dwEGtwb0S4E) | 35 | | 29.05.2025 | Work on course assignments | Павел, Николай | | 36 | | 05.06.2025 | Work on/Present course assignments | Павел, Николай | | 37 | | 12.06.2025 | Present course assignments | Павел, Николай | | 38 | 39 | [*Академичен календар](https://www.uni-sofia.bg/index.php/bul/studenti/akademichen_kalendar) 40 | 41 | 42 | Slot is always the same: 17:15 - 21:00 43 | 44 | 45 | * Course assignments = присъствено време, в което трябва да представите напредъка си и може да получите помощ от преподавателите 46 | * Present course assignments = възможни дати за финално представяне на курсовите проекти. Предвидени са няколко дати поради големината на групата и скоростта с която различните участници завършват проектите. 47 | -------------------------------------------------------------------------------- /brainstorming2020.md: -------------------------------------------------------------------------------- 1 | ## Lecture 1 2 | - slide #5: change picture & numbers 3 | - slide #10: look for more recent cool consumer IoT use case 4 | - slide #12: change pictures to show off what we've done previous years 5 | 6 | ## Lecture 2 7 | - Migrate ESP8266 to ESP32 8 | 9 | ## Lecture 3 10 | - add potentiometer slide & remove gyro 11 | 12 | ## Lecture 4 13 | - Add more displays 14 | 15 | ## Lecture 5 - split to intro (wired stuff + internet - needed for exercises and move as #2) second part (advanced: bluetooth, LoRa) 16 | - cut a bit from the theoretical content 17 | - More details about UART (mode of communication, master/slave, comm flow ...) 18 | - shorten the Bluetooth slides and update for BT5 19 | 20 | ## Lecture 6 21 | - this is part 2 with focus on Bluetooth and LoRa 22 | 23 | ## Lecture 7 24 | - move after lecture 4 25 | 26 | ## Lecture 9 27 | - new onboarding libraries (WiFi manager etc) 28 | 29 | ## Lecture 10 30 | - Visualization (plotly) 31 | - Elaborate IoT data storage/management 32 | - hosted (e.g. beebot or [Amazon Dynamo](https://aws.amazon.com/blogs/database/design-patterns-for-high-volume-time-series-data-in-amazon-dynamodb/) ) 33 | - Postgres 34 | - Prometheus 35 | - Parquet & (Spark/Dask) 36 | -------------------------------------------------------------------------------- /images/iot-on-youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmi/iot-course/de2426210b67a99022288a3655b8c4562d125201/images/iot-on-youtube.png -------------------------------------------------------------------------------- /scripts/convert.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | df = pd.read_csv("applicants.csv") 4 | 5 | unique_emails = [x.strip() for x in df['email'].unique()] 6 | print(len(unique_emails)) 7 | print( ";".join( unique_emails )) --------------------------------------------------------------------------------