<h3> ESP32 Workshop </h3> <p> Materials needed for this tutorial: <ul> <li>ESP32 Board </li> <li>Breadboard</li> <li>LED, 470 Ohm Resistor</li> </ul> </p> <p> The previous tutorial showed how to build a web interface to control your ESP32 over a Local Area Network. If you want to talk to your ESP32 from outside your LAN, you'll need to do a bit more work. There are many options: </p> <ul> <li> Build a full-stack server with a Model View Controller (MVC) architecture. This requires you to have (i.e. purchase) hosting services from e.g., BlueHost or DigitalOcean. Here's a <a href='https://randomnerdtutorials.com/control-esp32-esp8266-gpios-from-anywhere/'>tutorial</a> that walks through this method. Other useful tools for this method may include <a href='https://www.ibm.com/cloud-computing/bluemix/'> IBM</a> or <a href='https://aws.amazon.com/iot/'>Amazon Web Services</a>. </li> <li> Use a 3rd party platform designed to allow for a server-less IoT. Examples include <a href='https://io.adafruit.com/'>Adafruit IO</a>, <a href='https://thingspeak.com/'>ThingSpeak</a>, etc. </li> <li> Use a service like <a href='https://ifttt.com/'>If This, Then That (IFTTT)</a> to manage websocket connections. This service has gotten a bit more "business-oriented" than the previous examples, and doesn't allow direct or low-level control over your IoT devices (at least not without subscribing). It does feature lots of integrations to applications like <a href='https://randomnerdtutorials.com/esp32-esp8266-publish-sensor-readings-to-google-sheets/'>Google Sheets</a>, which you can use for data logging. It might also be the best choice if you want to do things like send an email every time an event is triggered. </li> <li> A final option is to use a 3rd party platform that acts as a general-purpose database for your IoT project. We'll use <a href='https://firebase.google.com/'>Google Firebase</a> for this. Like the other 3rd party platforms, we'll be able to talk to your device from anywhere in the world. But we can also talk to the Firebase Realtime Database from personal webpages, or build <a href='https://github.com/nathanmelenbrink/artg2260/blob/45924db6e60abae73a9ead30eaee0fd356d31b24/09_media/test.html'>a full-fledged app</a> with logins and permissions on top of it. </li> </ul> <p>Note: The following tutorial is a bit outdated. For working with Firebase, I recommend starting with <a href='https://randomnerdtutorials.com/esp32-firebase-realtime-database/'>this tutorial</a> from RandomNerd. There are additional tutorials on that site that explore other Firebase features as well. </p> <p> The first step is to head to <a href='https://firebase.google.com/'>Firebase</a> and sign in with your Google account. Click "Get Started" and then "Add Project". Next, specify your project name (I called mine ESP32-LED), which will be used to generate a url (like https://esp32-led-9a0ab.firebaseio.com) where you can access your project database. You can opt in to Google Analytics if you wish. Click OK; you should be taken to the Firebase console page for your project. Click "Realtime Database" from the panel on the left. </p> <img src='./fb1.png' alt='firebase screen grab'> <p> Scroll down to Realtime Database and click "Create database". For the Security rules options, select "Start in test mode" (you can change this later). Your Database console should now look something like this: </p> <img src='./fb2.png' alt='firebase database'> <p>Write down the URL that points to your database (https://esp32-led-9a0ab.firebaseio.com) . You are looking at the root of your database, which is "null" because there isn't anything there yet. First let's change permissions (click "Rules" and set both read and write to "true"). Next we need to create a secret key to give to our Huzzah board so it can access this database. Click the gear icon next to "Project Overview" and select "Project settings". On the "Project settings" page, click "Service accounts" and then "Database secrets":</p> <img src='./fb3.png' alt='firebase database'> <p>Hover over the secret key, and select "Show". Copy this and save it somewhere to use in later steps. Also make sure to write down the auto-generated URL where you can access your database (something like esp32-led-9a0ab.firebaseio.com). </p> <p>Set up your circuit so that there is an LED attached to pin 5. In Arduino IDE, make sure you've installed the necessary libraries for ESP32 <a href='./huzzah1.html'>(see previous step if not)</a>.</p> <p>Additionally, we need to add a couple libraries in order to talk to Firebase. Search and install the Firebase ESP32 Client by Mobizt, as well as the ArduinoJson library (version 6). </p> <p>In Arduino IDE, we can start with some of the WiFi library boilerplate code that we used in the last example (no need to start a server instance this time). Also, paste in your key and URL from Firebase. To learn more about how to use the FirebaseESP32 library, check <a href='https://github.com/mobizt/Firebase-ESP32'>the documentation</a>. </p> <pre><code> #include &lt;WiFi.h&gt; // esp32 library #include &lt;FirebaseESP32.h&gt; // firebase library #define FIREBASE_HOST "esp32-led-9a0ab.firebaseio.com" // the project name address from firebase id #define FIREBASE_AUTH "" // the secret key generated from firebase #define WIFI_SSID "" // input your home or public wifi name #define WIFI_PASSWORD "" // password of wifi ssid String fireString = ""; // led status received from firebase int ledpin = 5; //Define FirebaseESP32 data object FirebaseData firebaseData; void setup() { Serial.begin(115200); delay(1000); pinMode(ledpin, OUTPUT); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // try to connect with wifi Serial.print("Connecting to "); Serial.print(WIFI_SSID); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("Connected to "); Serial.println(WIFI_SSID); Serial.print("IP Address is : "); Serial.println(WiFi.localIP()); // print local IP address Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); // connect to firebase Firebase.reconnectWiFi(true); Firebase.set(firebaseData, "/LED_STATUS", "OFF"); // set initial string of "OFF" } void loop() { Firebase.get(firebaseData, "/LED_STATUS"); // get led status input from firebase fireString = firebaseData.stringData(); // change to e.g. intData() or boolData() Serial.println(fireString); if (fireString == "ON") { // compare the input of led status received from firebase Serial.println("Led Turned ON"); digitalWrite(ledpin, HIGH); // make output led ON } else if (fireString == "OFF") { // compare the input of led status received from firebase Serial.println("Led Turned OFF"); digitalWrite(ledpin, LOW); // make output led OFF } else { Serial.println("Please send ON/OFF"); } delay(1000); // not strictly necessary } </code></pre> <p> After modifying and uploading the above code, open your Serial monitor. In your browser, go to the Realtime Database console, where you should see a new field called "LED_STATUS" that is set to "OFF". Try changing it to "ON" (case sensitive) and observe the results. You can now turn on this LED from anywhere in the world where you have internet access! </p> <h3> Web Interface</h3> <p> While we can now talk to our device remotely, directly meddling with the database isn't exactly a smooth UI. Let's make a simple web interface to do this. </p> <p> Save the code below as a new HTML file (e.g., in your Week 10 folder). On your Firebase console page, look under where it says "Get started by adding Firebase to your app" and click the Web icon (&lt;/&gt;). On the next page, make a name for your app (like LED Toggle), and then copy the auto-generated configuration code into the firebaseConfig variable below. </p> ``` <!doctype html> <html class="no-js" lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>PHYSCI 70: Introduction to Digital Fabrication</title> </head> <body> <button id="turn-on" name="turnon">Turn On</button> <button id="turn-off" name="turnoff">Turn Off</button> <!-- The core Firebase JS SDK is always required and must be listed first --> <script src="https://www.gstatic.com/firebasejs/7.13.2/firebase-app.js"></script> <!-- TODO: Add SDKs for Firebase products that you want to use https://firebase.google.com/docs/web/setup#available-libraries --> <script src="https://www.gstatic.com/firebasejs/7.13.2/firebase-database.js"></script> <script> // Your web app's Firebase configuration var firebaseConfig = { apiKey: "REPLACE_WITH_YOUR_OWN", authDomain: "REPLACE_WITH_YOUR_OWN", databaseURL: "REPLACE_WITH_YOUR_OWN", projectId: "REPLACE_WITH_YOUR_OWN", storageBucket: "REPLACE_WITH_YOUR_OWN", messagingSenderId: "REPLACE_WITH_YOUR_OWN", appId: "REPLACE_WITH_YOUR_OWN" }; // Initialize Firebase firebase.initializeApp(firebaseConfig); // Get a database reference to our blog var ref = firebase.database().ref("/"); // make the buttons call the function below document.getElementById('turn-on').addEventListener('click', turnOn, false); document.getElementById('turn-off').addEventListener('click', turnOff, false); function turnOn(){ console.log("turning on"); ref.update({ "LED_STATUS": "ON" }); } function turnOff(){ console.log("turning off"); ref.update({ "LED_STATUS": "OFF" }); } </script> </body> ``` Save your code, commit and push as usual. Navigate to your new HTML page, and try turning the LED on and off. Here's a <a href='./firebase_demo.html'> live demo</a>. ### Controlling a Servo Motor We can modify the previous example to control a servo motor instead. The Arduino code is below, and the <a href='./servo_demo.html'> live demo is here</a>. ``` #include <WiFi.h> // esp32 library #include <FirebaseESP32.h> // firebase library #include <ESP32Servo.h> #define FIREBASE_HOST "" // the project name address from firebase id #define FIREBASE_AUTH "" // the secret key generated from firebase #define WIFI_SSID "" // input your home or public wifi name #define WIFI_PASSWORD "" // password of wifi ssid int fireInt = 0; // led status received from firebase const int ServoPin = 32; Servo myservo; // create servo object to control a servo //Define FirebaseESP32 data object FirebaseData firebaseData; void setup() { Serial.begin(115200); delay(1000); pinMode(ServoPin, OUTPUT); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // try to connect with wifi Serial.print("Connecting to "); Serial.print(WIFI_SSID); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("Connected to "); Serial.println(WIFI_SSID); Serial.print("IP Address is : "); Serial.println(WiFi.localIP()); // print local IP address Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); // connect to firebase Firebase.reconnectWiFi(true); Firebase.set(firebaseData, "/SERVO_ANGLE", fireInt); // set initial string of "OFF" myservo.attach(ServoPin); // attach servo to pin } void loop() { Firebase.get(firebaseData, "/SERVO_ANGLE"); // get led status input from firebase fireInt = firebaseData.intData(); // change to e.g. intData() or boolData() myservo.write(fireInt); delay(1000); // not strictly necessary } ```