Thimble Learning Platform
Back to full view

Weather Station 4

Introduction

The fourth and final kit in the weather station series, this kit is a weather proof enclosure.

Objectives

  • Learn about weather.
  • Construct a weather proof enclosure.
  • Create a mesh network.
  • Link two Arduinos together.
  • Have fun!
  • I've Never Used an Arduino

    Then this is a great place to start! If you're already familiar with setting up the Arduino and the IDE, you can skip to the next section.

    Terms 

    So when we talk about Arduino, the Arduino IDE, and coding, there are a lot of words being thrown around. This section will clear all of those up and get you ready to start building!

    Arduino 

    The Arduino is a electronics prototyping platform. That means it's a flexible platform for building, testing, and, of course, prototyping electronics. That could be simple LEDs that light up at night, or advanced robots. When we talk about the Arduino we are talking about the physical board itself. The one that comes in this kit is red, but they come in many different shapes and colors. The Arduino brand and original board were created by arduino.cc and you can read more about the details of its history here.

    Arduino IDE 

    The Arduino IDE, or Integrated Development Environment, is not hardware, but a piece of software. If you wanted to write an essay, you might use Microsoft Word or Google Docs. If you wanted to edit pictures, you'd probably use Photoshop or Paint.net. If you want to program code for the Arduino, you'd use the Arduino IDE. Its a computer program (tool) that let's you develop and test out code. Once written, the code can be upload to the physical Arduino where it will stay until you upload new code.

    Download

    Since it is a program, you'll need to install it.

    For Windows computers use this link Windows Installer

    For Mac computers use this link Mac Installer

    After following each link, press the Just Download button to begin downloading the Arduino IDE. The Mac version has a few more steps and we have a video just for that.

    Mac Installation
    For Mac users

    Installation

    Open the exe you downloaded. You'll see a screen asking you to agree to their license. You can press I Agree.

    LicenseLicense

    Next up are the installation options. The Install USB Drivers lets the Arduino board communicate with the IDE. We definitely want this. The Associate .ino files makes any Arduino file on your computer open up to the Arduino IDE. Very helpful, so we'll keep that too. Press Next >.

    OptionsOptions

    Now you are being asked where you'd like the Arduino IDE program installed. I don't mind it in the standard Program Files so I just press Install. You can change where it will be installed, just remember what you chose. I recommend not changing it.

    FolderFolder

    Now the IDE is installing. Let it complete then move on to the next section.

    InstallingInstalling

    Arduino IDE 101

    Open up the Arduino IDE for the first time. So, let's figure out what's what.

    Arduino IDEArduino IDE

    There is a mostly empty space in the middle that has this text:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void setup() {
      // put your setup code here, to run once:
    
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    

    This is a simple Arduino Sketch. A Sketch is code you write that will later be uploaded to the Arduino board.

    There are few steps to go from code written in a sketch to code that runs on the Arduino board. Those are Verify > Compile > Upload.

    All of these you can get to by going under Sketch on the top bar of the program. Or but using the Checkmark and Arrow icons right below that. The Checkmark verifies your code will compile, and the arrow button uploads the code to the Arduino.

    Sketch
    Icons

    Verify - looks at your code and makes sure it can actually run. It checks that there are no errors or things out of place. If your code will work, it goes to the Compile stage.

    Compile - The code you've written is great for human. It is readable and hopefully understandable. But this isn't great for a machine ie the Arduino. The Compile stage takes your written code and translates into something that the Arduino can understand and run, called machine code. It saves that compiled file and tried to Upload it to the board.

    Upload - This takes the compiled files and tries to send it to a plugged in Arduino. The IDE doesn't know where you've plugged in your Arduino or what kind it is. You have to tell it. I'll show you how to set that up in the next section.

    Arduino Board Setup

    For this section make sure your Arduino Board that came with your kit is plugged in. Use the included micro USB cable to plug your Arduino into any free USB port on you computer.

    Navigate to the Tools section at the top of the Arduino IDE.

    ToolsTools

    You'll be greeted with a scary drop down. To setup your Arduino to accept uploads, do the following: Go to Board: and make sure Arduino/Genuino Uno is selected.

    Next is the Port. For Mac users refer to the video for these instructions. With your Arduino plugged in, you'll see some options. Mine says COM 15. This is the channel that the IDE will use to communicate with your Arduino. If you have a lot of COM # devices and don't know which is your Arduino, unplug your Arduino and take note of that numbers are there. Then plug it back in. Whichever is the new one in the list is your Arduino. Select that port.

    With the board and port selected and ready to go, let's upload our first sketch.

    Sketches

    We are going to upload a simple sketch to make an LED on the board blink. Head to File > Examples > Basics > Blink . You should see this sketch.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /*
      Blink
    
      Turns an LED on for one second, then off for one second, repeatedly.
    
      Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
      it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
      the correct LED pin independent of which board is used.
      If you want to know what pin the on-board LED is connected to on your Arduino
      model, check the Technical Specs of your board at:
      https://www.arduino.cc/en/Main/Products
    
      modified 8 May 2014
      by Scott Fitzgerald
      modified 2 Sep 2016
      by Arturo Guadalupi
      modified 8 Sep 2016
      by Colby Newman
    
      This example code is in the public domain.
    
      http://www.arduino.cc/en/Tutorial/Blink
    */
    
    // the setup function runs once when you press reset or power the board
    void setup() {
      // initialize digital pin LED_BUILTIN as an output.
      pinMode(LED_BUILTIN, OUTPUT);
    }
    
    // the loop function runs over and over again forever
    void loop() {
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);                       // wait for a second
      digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);                       // wait for a second
    }
    

    Don't worry about the coding for now. Let's upload this sketch. You can press the Arrow icon, go to Sketch then Upload, or you can use the shortcut Ctrl+U in order to upload the code. Your sketch will auto-verify, compile, then upload to your Arduino board.

    You will see the message Done uploading and your board should now have a blinking light.

    Uploading Sketches and Code From Thimble 

    We provide example code for all our projects. To use those you'll need to copy them from our website. Then, go into the Arduino IDE, File > New. It's best to then delete all the code already there in the sketch before you paste our code in, as that will avoid any errors from copying over the old code.

    Serial Plotter

    You'll be asked to use the Serial Plotter on some projects. This reads any information coming from the Arduino and displays it on a graph. It can only be accessed after you've uploaded your code. It is in the Tools menu.

    Troubleshooting 

    The most common issues are solved by double checking your Board and Port settings.

    Libraries

    What are Libraries? 

    Libraries are a collection of code that has already been written. We use them when we want to add functionality without have to write everything from scratch.

    Some the projects in this set need libraries so this section will show you how to install those.

    Libraries to be downloaded 

    Our libraries come in the form of zip files that need to be downloaded but NOT unzipped.

    Low Power - This is for the sleeping the Arduino.

    Adding Them to the Arduino IDE 

    Open up the Arduino IDE and go to Sketch > Include Library > Add .ZIP Library.... After that navigate to the zip files and add them one by one. And that's it!

    Add a LibraryAdd a Library

    What Should I Have Received?

    List of Parts 

    This is a list of all the parts you should have received in your Weather Station 4 kit. Your WiFi module might look different.

    Parts

    All Parts x Qty
    Plastic Louvers x 2
    Arduino x 1
    Bag of Hardware x 1
    WiFi Module x 1
    Cable x 1
    Acrylic Parts x 15

    Additional parts

    You should also have received a sheet of six stickers and a postcard with instructions.

    Stickers
    Postcard
    First Time WiFi Module Setup

    Start 

    Since you have received a new WiFi Module it must be setup just like we did in Weather Station 2.

    Both WiFi modules side by sideBoth WiFi modules side by side

    Modules 

    Gather the following parts to complete this project.

    Parts

    All Parts x Qty
    WiFi x 1
    Cable x 1

    WiFi Module 

    Take a cable and unwrap it. Plug one side into the WiFi socket and the other into any Digital socket.

    Parts needed
    Take a cable
    Unwrap it
    Plug one side into the WiFi socket
    The other into any Digital socket

    Upload

    Upload the following code. The example below uses the D8 digital pin.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include <SoftwareSerial.h>
    #define TIMEOUT 10000
    
    //Creates serial communication object
    SoftwareSerial espSerial(8, 9); // RX, TX
    
    String response = "";
    
    int baudCount = 0;
    
    bool timedout = false;
    bool set = false;
    bool confirmed = false;
    
    unsigned long timestamp = 0;
    
    void setup() {
      // Open serial communications
      Serial.begin(9600);
      espSerial.begin(115200);
      Serial.println("Testing WiFi Module...");
      espSerial.write("AT\r\n");
    }
    
    
    
    void loop() { // run over and over
      while (response == "" && !timedout) {
        if (espSerial.available()) {
          delay(200);
          espSerial.write("AT\r\n");
          //Display in the Serial Monitor
          response = espSerial.readString();
        }
        if(millis() > (TIMEOUT + timestamp)){
          timedout = true;
          timestamp = millis();
        }
      }
      if(timedout && !set && !confirmed){
        Serial.println("Timeout communicating with WiFi Module at 115200 Baud");
      }
    
      if (response.endsWith("OK\r\n") && !set && !timedout) {
        Serial.println("Found WiFi Module. Setting Baudrate to 9600...");
        espSerial.write("AT+UART_DEF=9600,8,1,0,0\r\n");
        set = true;
        response = "";
        espSerial.end();
        espSerial.begin(9600);
        delay(200);
        espSerial.write("AT\r\n");
      }
      if (!set && timedout) {
        Serial.println("Setting Baudrate to 9600...");
        espSerial.write("AT+UART_DEF=9600,8,1,0,0\r\n");
        set = true;
        response = "";
        espSerial.end();
        espSerial.begin(9600);
        delay(200);
        espSerial.write("AT\r\n");
        timestamp = millis();
        timedout = false;
      }
    
      if (response.endsWith("OK\r\n") && set && !confirmed) {
        Serial.println("WiFi Module configured to 9600 baud");
        delay(200);
        Serial.println("Ready for Thimble use");
        confirmed = true;
      }
    }
    

    Did it work? 

    Open the Serial Monitor after uploading to see if it worked. You want to see this output text...

    Download file Copy to clipboard
    1
    2
    3
    4
    Testing WiFi Module...
    Found WiFi Module. Setting Baudrate to 9600...
    WiFi Module configured to 9600 baud
    Ready for Thimble use
    

    I only see Testing WiFi Module

    Press the reset button on your Arduino. If still only see Testing ESP... run the code below.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #include <SoftwareSerial.h>
    
    //Creates serial communication object
    SoftwareSerial espSerial(8, 9); // RX, TX
    
    String response = "";
    
    bool confirmed = false;
    
    void setup() {
      // Open serial communications
      Serial.begin(9600);
      espSerial.begin(9600);
      Serial.println("Testing WiFi Module...");
      espSerial.write("at\r\n");
    }
    
    
    void loop() { // run over and over
      while (response == "") {
        if (espSerial.available()) {
          delay(200);
          espSerial.write("at\r\n");
          //Display in the Serial Monitor
          response = espSerial.readString();
        }
      }
    
      if (response.endsWith("OK\r\n") && !confirmed) {
        Serial.println("Your WiFi Module is working!");
        Serial.println("You are done with this step");
        confirmed = true;
      }
    }
    

    Did it work?

    Open the Serial Monitor after uploading to see if it worked. If you see this...

    Download file Copy to clipboard
    1
    2
    3
    Testing ESP...
    Your WiFi Module is working!
    You are done with this step
    

    ...then you are ready to go. If not, then double check you are using D8 as your socket and run the first code again.

    Two Arduino Messaging System

    Messaging System 

    By the end of these sections you'll be able to create a system that can send and receive messages between multiple Arduinos! In the picture below, one Arduino uses a keyboard and the serial monitor for its input and output. While the other uses a potentiometer, button, and the LCD display. This simple network is possible due to the extra Arduino and WiFi module included in the kit.

    Networking 101 

    When you type in a web address and press enter a lot of things happen before you see the page. Your request is converted into 1's and 0's and is sent down a wire to the server that has the web page you're looking for. The web page is then sent back to you as 1's and 0's, and then your browser converts those 1's and 0's into a webpage that you can see.

    The abstraction commonly used to explain this process is called the Open Systems Interconneciton Model. Or OSI model for short. This is not the end all be all for how information is transferred in the Internet but it's pretty spot on for most things.

    OSI Model 

    The OSI Model is split into 7 layers. The layer above needs the layer below and the layer below only serves the layer above. Each layer has one objective in the process of transferring data. Once it fulfills that, whatever else needs to be done is part of another layer.

    OSI ModelOSI Model

    Layer 1 - Physical Layer

    The Physical Layer is responsible for taking 1's and 0's and converting them into a signal and vice versa. This could mean sending electricity down a wire, generating waves for radio, or sending light down a fiber for fiber optics. This layer takes a digital signal and coverts it into some physical means of transmitting. What's the data it's sending? Doesn't care. Where is it going? Doesn't care. Those questions are for a higher layers.

    Physical LayerPhysical Layer

    Layer 2 - Data Link Layer

    The Data Link Layer is responsible for getting the data to the next step in a network. This layer adds the address of the physical hardware that Layer 1 will send to. It is concerned about one step in a relay race. The place where the Data Link Layer decides to send data might not be the final destination. The Data Link layer concerns itself with hop to hop delivery. So how does data get from a certain source to it's final destination? That's a questions for a higher layer.

    Data Link LayerData Link Layer

    Layer 3 - Network Layer

    The Network Layer is responsible for figuring out the path data will take to get from its source to its destination. The network layer will figure out what devices are connected to what and figure out the best path from getting to point A to point B. It does this with Internet Protocol, or IP, address. There might not be a direct path but by using a destination IP the data will eventually find its way. Similar to ordering a package. The person shipping a package is often not the one delivering it. There are many stops and transfer but by knowing where the package is going it will get closer and closer until it arrives. Does the package have the correct contents? If so then who do you give it to? Those questions are for a higher layers.

    Network LayerNetwork Layer

    Layer 4 - Transport Layer

    The Transport Layer is responsible for making sure data has no errors and for sending good data to the person who requested it. There are two main protocols for dealing with this. They are TCP and UDP. TCP makes sure that each packet of data arrives to it's destination and in the right order. When you request information from a web page you want all of the information you asked for. UDP is used when speed is required over accuracy. A video call or live stream might use UDP since you want the most current information as fast as possible, but it doesn't really matter if a small piece of data gets lost, it's old data now and we can just skip over it.

    Once a packet is determined to be good. The Transport Layer also sends it to the right place. A package might be delivered to the right building but until it gets to the specific person who ordered it, its journey isn't complete.

    Transport LayerTransport Layer

    A Breather

    There are 3 more layers to the OSI model. We won't be implementing them in this project but we will come back to them later.

    Summary 

    Let's say you have some data to send. The Transport Layer adds information that is used to check things like whether the data arrived in the right order and whether it was damaged along the way. It is then passed to the Network Layer. The Network Layer adds the source and destination before the data, and then passes it to the Data Link Layer. The Data Link Layer finds the best point to send the data next. If it can it will send it directly to the destination but usually the trip takes a few hops. The data is sent from one device to another until it finally reaches its destination. With each hop the Physical Layer converts the data from a signal and then back into a signal to be transmitted. This keeps happening until the packet arrives at the correct location.

    Two Arduino Messaging System - Hardware

    Messaging System 

    By the end of this section you'll be able to create a system that can send and receive messages between multiple Arduinos! In the picture below, one Arduino uses a keyboard and the serial monitor for its input and output. While the other uses a potentiometer, button, and the LCD display. This simple network is possible due to the extra Arduino and WiFi module included in the kit.

    Modules 

    Gather the following parts to complete this project.

    Parts

    All Parts x Qty
    Arduino With Base Shield x 1
    Ardunio Without Base Shield x 1
    WiFi Module x 2
    RGB LCD display x 1
    Potentiometer x 1
    Button x 1
    Cables x 4

    Project Specifications 

    Lets go over the design requirements and constraints of our system.

    Requirements

    • Two Arduino communication
    • Acknowledgments when messages are received
    • The ability to write messages and receive them at the same time

    Constraints

    • Only one Arduino can use the base shield
    • Only one Arduino can be using the Serial Monitor
    • Both Arduinos need input and output systems

    Project Layout 

    With our requirements and constraints laid out lets get to work sketching out the design. Each Arduino will need an input and output. For the one attached to the computer it is able to use the Serial Monitor. With the Serial Monitor we send messages as well as see them. This takes care of the inputs and outputs.

    For the other Arduino, I've elected to use LCD Display to the output and a potentiometer and button for the general input. There are a few options we could have used the these. Such as, an LED blinking Morse code as the output or perhaps using many buttons as the input. Feel free to experiment and try your own solutions.

    Arduinos Assemble 

    Starting with the Arduino without the base shield. Take a cable and unwrap it. Plug one side into the WiFi Module and the other into one of the I2C sockets found natively on the Arduino. We can set that one aside.

    All the parts you'll need
    Starting with this Arduino
    Take a cable
    Unwrap it
    Plug one side into the WiFi Module
    The other into one of the I2C sockets
    Good job!
    We can set that one aside
    We can set that one aside

    Now grab the remaining Arduino with the base shield attached. Take a cable and unwrap it. Plug one side into the WiFi Module and the other into D8.

    Remaining parts
    Take a cable
    Unwrap it
    Plug one side into the WiFi Module
    The other into D8

    Take a cable and unwrap it. Plug one side into the button module and the other into D4. Take the another cable and unwrap it. Plug one side into the potentiometer module and the other into A0. Take the last cable and unwrap it. Plug one side into the LCD DIsplay and the other into any I2C.

    Let's keep going
    Take a cable
    Unwrap it
    Plug one side into the Button Module
    The other into D4
    Take a cable
    Unwrap it
    Plug one side into the Potentiometer Module
    The other into A0
    Take a cable
    Unwrap it
    Plug one side into the LCD DIsplay
    The other into I2C
    Ready for code

    Next Section 

    This is the end of the assembly for the Two Arduino Messaging System. Continue on to start coding.

    Two Arduino Messaging System - Software

    Layer by Layer 

    We'll be building up our messaging system layer by layer. Starting with the physical layer through the transport layer. We'll be using this same system for our Weather Station as well as a couple more projects in this kit.

    Creating a Network and Receiver 

    This is the first project with two Arduinos. There is one with a black base shield and one without. Make sure you know which is which. In order to test the Arduinos as we make code for them, you'll need to power both. It's easiest to have one connected to the computer and other connected to power my battery or wall charger.

    A Network

    Our first step is to create a WiFi network. The code below adds sections for the physical and data link layer. Starting the WiFi module itself enabled the WiFi radio and this the physical layer. The same chip that handles that also takes care of the data link layer. We are using the WiFi standard so a lot of work in terms of radio wave generation and transmission has been done for us. Plug in the Arduino without the base shield and upload the following code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    //All the libraries used
    #include <WiFiEsp.h>
    #include "SoftwareSerial.h"
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(A5, A4); // RX, TX
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    
    //WiFi network settings
    char ssid[] = "homebase";            // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for ESP module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.configAP(apIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Make a network
        status =  WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
      }
    
      //Print WiFi status
      Serial.println("Network Created");
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    

    Observe

    Open up the Serial Monitor. The Arduino will start up the WiFi module then our network will be created. Check on a phone or computer that you see our network called homebase.

    Modify

    You can change the ssid[] or name of the network as well as the pass[] or password of the network.

    Receiver

    With this code we can see the network we made but it doesn't do anything. The code below adds sections for the network and transport layer. You can see that we have defined our IP address as well as set up a listener for any UDP packets.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    //All the libraries used
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(A5, A4); // RX, TX
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    
    //WiFi network settings
    char ssid[] = "homebase";            // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    //Ports to be used
    unsigned int listeningPort = 10003;  // local port to listen on
    unsigned int sendingPort = 10002;  // local port to listen on
    char packetBuffer[255];          // buffer to hold incoming packet
    char ReplyBuffer[] = "ACK";
    
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for ESP module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.configAP(apIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Make a network
        status =  WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
      }
    
      //Print WiFi status
      Serial.println("Network Created");
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    }
    
    void loop() {
      // if there's data available, read the packet
      int packetSize = Udp.parsePacket();
      if (packetSize) {
        Serial.print("Received packet of size ");
        Serial.println(packetSize);
        Serial.print("From ");
        IPAddress remoteIp = Udp.remoteIP();
        Serial.print(remoteIp);
        Serial.print(", port ");
        Serial.println(Udp.remotePort());
    
        // read the packet into packetBufffer
        int len = Udp.read(packetBuffer, 255);
        if (len > 0) {
          packetBuffer[len] = 0;
        }
        Serial.println("Contents:");
        Serial.println(packetBuffer);
    
        // send a reply, to the IP address and port that sent us the packet we received
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write(ReplyBuffer);
        Udp.endPacket();
      }
    
    }
    

    Observe

    Open up the Serial Monitor. The Arduino will start up the WiFi module then our network will be created. We can now see an additional step. The Arduino is waiting to pick up and report any UDP packets.

    A Simple Sender 

    With our network created and receiver ready for information, we need something to send data. Unplug the Arduino without the shield and replace it with the Arduino with the shield.

    Send on Press

    This used the button as a trigger for sending a packet. When the button is pressed a message is converted into a UDP packet. Upload the following code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    //All the libraries used
    #include <OneButton.h>
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    
    //Definable sockets for modules
    #define buttonSocket 4
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(8, 9); // RX, TX
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    IPAddress stationIP = IPAddress(192, 168, 111, 112);
    
    
    //WiFi network settings
    char ssid[] = "homebase";        // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    //Ports to be used
    unsigned int listeningPort = 10002;  // local port to listen on
    unsigned int sendingPort = 10003;  // local port to sent on
    
    //Arrays for storing sent and received packets
    char packetBuffer[255];          // buffer to hold incoming packet
    char ReplyBuffer[] = "ACK";      // a string to send back
    char messageToSend[] = "Hello World";
    
    //Creates button object
    OneButton button = OneButton(buttonSocket, false);
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for WiFi module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.config(stationIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Print which SSID it's trying to connect to
        Serial.print(F("Attempting to connect to WPA SSID: "));
        Serial.println(ssid);
        // Connect to WPA/WPA2 network
        status = WiFi.begin(ssid, pass);
      }
    
      //Print WiFi status
      Serial.println(F("Connected to wifi"));
      printWifiStatus();
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    
      // Print out which port
      Serial.print(F("Sending on port "));
      Serial.println(sendingPort);
    
      // Create button event functions
      button.attachClick(singlePress);
    }
    
    void loop() {
      // Update button events
      button.tick();
    
    }
    
    void singlePress() {
    
      //Print out what the WiFi Module is sending
      Serial.println(F("Sending Packets"));
      Serial.print(F("Sending to: "));
      Serial.println(apIP);
      Serial.print(F("On Port:  "));
      Serial.println(sendingPort);
      Serial.print(F("Message is:  "));
      Serial.println(messageToSend);
    
      //Send the message
      Udp.beginPacket(apIP, sendingPort);
      Udp.write(messageToSend);
      Udp.endPacket();
    }
    
    void printWifiStatus() {
      // print the SSID of the network you're attached to:
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
    
      // print your WiFi shield's IP address:
      IPAddress ip = WiFi.localIP();
      Serial.print("IP Address: ");
      Serial.println(ip);
    
      // print the received signal strength:
      long rssi = WiFi.RSSI();
      Serial.print("signal strength (RSSI):");
      Serial.print(rssi);
      Serial.println(" dBm");
    }
    

    Observe

    Open the Serial Monitor. This Arduino will connect to the network we made before. Only connected you can press the button to send a message. When you see that the message Hello World was sent then we know it's working. Swap the Arduino so that the one without the base board is connected to the computer. Open the Serial Monitor again. Wait for the network to come online. Now press the button on the other Arduino. The message will send and be delivered to the other Arduino before being displayed on the Serial Monitor.

    Code uploaded
    About to press
    Pressed
    check Serial Monitor

    A Breather 

    This is the most basic set up for sending information over WiFi. In the next section, we'll talk about how to add more features to make this a real two way messaging system.

    TCP, UDP, UDP+

    What 

    In the overview, we spoke about TCP vs UDP. If we look at our Design Requirements, it states that we want Acknowledgments when messages are received. TCP sends acknowledgments but our previous section had us using UDP. The acknowledgment part of TCP is a bit complex and we don't need the full usage of it for our system. UDP is already implemented in the WiFiEsp library and building a system on top of that is a good learning experience. So that is why we are going to add simple acknowledgments to our use of UDP to created what I'm calling, UDP+.

    What are acknowledgments anyway?

    When a packet is sent from one device to another and you'd like to know if it got there, you would send an acknowledgment back. It's a special packet that is sent back to the source when a packet is received. TCP uses two of these. Device A sends a packet. Device B sends an acknowledgment that it received that packet. Then Device A sends an acknowledgment that it received Device B's acknowledgment. UDP sends a packet. That's it. All done. Our UDP+ will just send one acknowledgment packet.

    Transmissions and Timeouts 

    Not everything works out the first time. If the sender of a TCP packet doesn't hear back with an acknowledgment, or ACK packet, it will transmit it's data. If it still doesn't hear back it will transmit its data again. How long it waits before transmitting another packet is called its Timeout. It could try 2, 5, or any number of times to transmit data before it quits. That depends on what kind of system you are building.

    Serial Sending 

    While it might seem complex to take anything written into the Serial Monitor and capture it for use. The following code is all we need. When we write into the Serial Monitor and press enter, any characters are written into the serial port. The function Serial.available() returns 0 unless there is information in the serial port. Then it returns the number of bytes of information. If you wrote the word cat and pressed enter, the function would return a 3 . We are using the if statement of Serial.available() > 0 to trigger whenever this is information added. The Serial.readString() captures all the characters in the serial port and stores them in the variable called message . That variable is a string and for many purposes that would be fine. If wanted to write into the Serial Monitor and display that on an LED Display then we could with how it is. But since we are sending the message via UDP it must be converted from a string in to a char array. That last time does that. It operates on the message variable, and makes a copy as a char array called messageToSend .

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
        if (Serial.available() > 0) {
           //Store text in message
           message = Serial.readString();
           Serial.println("Sending message");
           .....
           message.toCharArray(messageToSend, sizeof messageToSend);
        }
    

    ACK Implementation 

    You can see in the diagrams above that when data is received an ACK packet should be sent immediately. In the first code block below we are checking to see if what the Arduino received, String(packetBuffer) , is equal to what an ACK packet looks like, String(ReplyBuffer) . If it does then the state is updated to SUCCESS because we received an ACK packet and the message got to its destination. If the data recieved was not an ACK packet then the state is set to RECEIVED because we received a real message. When that happens, you can see that first thing we do is to send an ACK packet back. ReplyBuffer store the ACK packet.

    First Code block

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
        //If the packets are an "ACK" message
        if (String(packetBuffer) == String(ReplyBuffer) && waitForACK) {
          // Update current state
          currentState = SUCCESS;
        }
        else {
          //If the packet are a text message
          currentState = RECEIVED;
        }
    

    Second Code Block

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
        // Instructions for RECEIVED state
        case RECEIVED:
          //Send "ACK" message
          sendData(ReplyBuffer, stationIP, sendingPort);
          Serial.println("Incoming Message");
          // Update current state
          currentState = SHOW;
          //End of case
          break;
    
    Full Two Arduino Messaging Code

    All Together 

    Below are the two pieces of code to complete this project.

    Arduino With Shield - Upload 

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    //All the libraries used
    #include <OneButton.h>
    #include <rgb_lcd.h>
    #include <Wire.h>
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    
    //Definable sockets for modules
    #define buttonSocket 4
    #define dialSocket A0
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(8, 9); // RX, TX
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP= IPAddress(192, 168, 111, 111);
    IPAddress stationIP= IPAddress(192, 168, 111, 112);
    IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
    IPAddress remoteIp;
    bool broadcasting = false;
    
    //WiFi network settings
    char ssid[] = "homebase";        // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    //Ports to be used
    unsigned int listeningPort = 10002;  // local port to listen on
    unsigned int sendingPort = 10003;  // local port to sent on
    
    //Arrays for storing sent and received packets
    char packetBuffer[255];          // buffer to hold incoming packet
    char ReplyBuffer[] = "ACK";      // a string to send back
    String message;
    char messageToSend[16];
    
    //Variables used to convert dial to letter
    int dialVal;
    int alphabetIndex;
    char charToShow;
    
    //Transmition variables
    bool waitForACK = false;
    int transmits = 0;
    //How many transmit attempts
    int transmitLimit = 2;
    unsigned long previousTransmit;
    //Time between attempts
    int interval = 1000;
    
    //States for state machine
    enum states {
      WRITING,
      RECEIVED,
      SENDING,
      SHOW,
      FAIL,
      SUCCESS
    };
    
    //Variable to keep track of states
    states currentState = WRITING;
    
    //Creates button object
    OneButton button = OneButton(buttonSocket, false);
    //Creates lcd display object
    rgb_lcd lcd;
    
    //LCD Display color variables
    const int colorR = 50;
    const int colorG = 50;
    const int colorB = 50;
    
    //Char array of every char in the alphabet
    const char alphabet[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
                             'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
                            };
    
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for WiFi module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.config(stationIP);
    
      // initalize the LCD Display
      lcd.begin(16, 2);
      // Set to defined color
      lcd.setRGB(colorR, colorG, colorB);
      //Start writing at the top right
      lcd.setCursor(0, 0);
      // Print message to display
      lcd.print(F("Setting up WiFi"));
    
    
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Print which SSID it's trying to connect to
        Serial.print(F("Attempting to connect to WPA SSID: "));
        Serial.println(ssid);
        // Connect to WPA/WPA2 network
        status = WiFi.begin(ssid, pass);
      }
    
      //Print WiFi status
      Serial.println(F("Connected to wifi"));
      printWifiStatus();
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    
      // Create button event functions
      button.attachClick(singlePress);
      button.attachDoubleClick(doublePress);
      button.attachLongPressStart(longPress);
      // Lower the double click time
      button.setClickTicks(250);
      //Clear any characters from LCD
      lcd.clear();
    }
    
    void loop() {
      // Update button events
      button.tick();
    
      //Check for incoming packets
      int packetSize = Udp.parsePacket();
    
      // If there are packets
      if (packetSize) {
        //Print out update
        Serial.println(F("Packets Received"));
        // read the packet into packetBufffer
        int len = Udp.read(packetBuffer, 255);
        if (len > 0) {
          packetBuffer[len] = 0;
        }
        //If the packets are an "ACK" message
        if (String(packetBuffer) == String(ReplyBuffer) && waitForACK) {
          // Update current state
          currentState = SUCCESS;
          //If the packet are a text message
        } else {
          //Send "ACK" message
          sendData(ReplyBuffer, apIP, sendingPort);
          //Clear any characters from LCD
          lcd.clear();
          // Set to defined color
          lcd.setRGB(0, 0, 128);
          //Start writing at the top right
          lcd.setCursor(0, 0);
          // Print message to display
          lcd.print("Incoming Message");
          //Start writing at the bottom right
          lcd.setCursor(0, 1);
          // Print message to display
          lcd.print("Press to Show");
          // Update current state
          currentState = RECEIVED;
        }
        // Addtional debugging info
        // Serial.print(F("Packets Rec: "));
        // Serial.println(packetBuffer);
      }
    
    
    
      //Beginning of state machine
      switch (currentState) {
        // Instructions for WRITING state
        case WRITING:
          //Read the dial position
          dialVal = analogRead(dialSocket);
          // Translate to number in the alphabet
          alphabetIndex = map(dialVal, 0, 1023, 25, 0);
          // Translate number to actual letter
          charToShow = alphabet[alphabetIndex];
          //Start writing at the top right
          lcd.setCursor(0, 0);
          // Print char to be written
          lcd.print(charToShow);
          //End of case
          break;
    
        // Instructions for SENDING state
        case SENDING:
          // If transmit attempts are over the limit
          if (transmits > transmitLimit && waitForACK) {
            // Update current state
            currentState = FAIL;
          }
          // If the interval has passed from the last transmit
          if (millis() - previousTransmit > interval && waitForACK) {
            // Send message on correct port
            sendData(messageToSend, apIP, sendingPort);
          }
          //End of case
          break;
    
        // Instructions for FAIL state
        case FAIL:
          //Stop waiting for "ACK" message because we won't get it
          waitForACK = false;
          lcd.clear();
          //Set screen to red
          lcd.setRGB(255, 0, 0);
          lcd.setCursor(0, 0);
          lcd.print(F("Transmit Failed"));
          Serial.println(F("Transmit Failed"));
          // Wait for 1.5 seconds to read message
          delay(1500);
          lcd.clear();
          lcd.setRGB(colorR, colorG, colorB);
          //Reprint the message to be sent
          lcd.setCursor(0, 1);
          lcd.print(message);
          // Update current state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for SUCCESS state
        case SUCCESS:
          //Stop waiting for "ACK" message because we got it
          waitForACK = false;
          lcd.clear();
          // Set screen to green
          lcd.setRGB(0, 255, 0);
          lcd.setCursor(0, 0);
          lcd.print(F("ACK Received"));
          Serial.println(F("ACK Received"));
          // Wait for 1.5 seconds to read message
          delay(1500);
          lcd.clear();
          //Clear message by setting equal to nothing
          message = "";
          //Reset all char in the char arrays to 0
          memset(packetBuffer, 0, sizeof packetBuffer);
          memset(messageToSend, 0, sizeof messageToSend);
    
          //Reset screen color
          lcd.setRGB(colorR, colorG, colorB);
          // Update current state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for RECEIVED state
        case RECEIVED:
          //Does nothing while waiting for input
          //End of case
          break;
    
        // Instructions for SHOW state
        case SHOW:
          //Does nothing while waiting for input
          //End of case
          break;
      };
    
    
    }
    
    //Instructions for a single press of the button
    void singlePress() {
      //Switch case because of state dependant instructions
      switch (currentState) {
        // Instructions for WRITING state
        case WRITING:
          //Add current char to message
          message = message + charToShow;
          //Print at bottom left
          lcd.setCursor(0, 1);
          //Rewrite message with new char
          lcd.print(message);
          //End of case
          break;
    
        // Instructions for FAIL state
        case FAIL:
          //Send user back to WRITING state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for SUCCESS state
        case SUCCESS:
          //Send user back to WRITING state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for RECEIVED state
        case RECEIVED:
          lcd.clear();
          //Set screen to blue
          lcd.setRGB(0, 0, 128);
          lcd.setCursor(0, 0);
          lcd.print("Message Contents");
          lcd.setCursor(0, 1);
          //Show the message in the packetBuffer
          lcd.print(packetBuffer);
          //Update state
          currentState = SHOW;
          //End of case
          break;
    
        //Send user back to SHOW state
        case SHOW:
          //Clear packetBuffer for new messages
          memset(packetBuffer, 0, sizeof packetBuffer);
          lcd.clear();
          lcd.setRGB(colorR, colorG, colorB);
          //Rewrite any unsent message text
          lcd.setCursor(0, 1);
          lcd.print(message);
          //Update state
          currentState = WRITING;
          //End of case
          break;
      }
    }
    
    //Instructions for a double press of the button
    void doublePress() {
      //Switch case because of state dependant instructions
      switch (currentState) {
        case WRITING:
          //Add a space to the message
          message = message + ' ';
          //Display new message
          lcd.setCursor(0, 1);
          lcd.print(message);
          break;
      }
    }
    
    //Instructions for a long press of the button
    void longPress() {
      //Switch case because of state dependant instructions
      switch (currentState) {
        case WRITING:
          lcd.setCursor(0, 1);
          lcd.print(F("Sending message"));
          //Set display to yellow
          lcd.setRGB(128, 128, 0);
    
          //Clear buffers for message about to be sent
          memset(packetBuffer, 0, sizeof packetBuffer);
          memset(messageToSend, 0, sizeof messageToSend);
    
          //Convert String message into a char array
          message.toCharArray(messageToSend, message.length() + 1);
          //Reset transmit attempts
          transmits = 0;
          //Start listening for an "ACK" packet
          waitForACK = true;
          //Update state
          currentState = SENDING;
          //End of case
          break;
      }
    }
    
    //Fucntion to send data
    void sendData(char mess[], IPAddress ip, int port) {
      //Toggle for extra info
      if (true) {
        Serial.println(F("Sending Packets"));
        Serial.print(F("Sending to: "));
        Serial.println(remoteIp);
        Serial.print(F("On Port:  "));
        Serial.println(sendingPort);
        Serial.print(F("Message is:  "));
        Serial.println(messageToSend);
      }
    
      //Toggle broadcasting vs direct ip to ip
      // Create temp ip variable
      IPAddress ipToUse;
      //If broadcasting is on
      if (broadcasting) {
        //Set destination ip to 0.0.0.0
        ipToUse = broadcastIP;
      } else {
        //Use other WiFi module ip
        ipToUse = ip;
      }
    
      //Update the last transmit time to now
      previousTransmit = millis();
      //Open packet to certain ip at certain port
      Udp.beginPacket(ipToUse, port);
      //Write message to packet
      Udp.write(mess);
      //End the packet
      Udp.endPacket();
      //Increase number of transmits
      transmits++;
    }
    
      void printWifiStatus() {
      // print the SSID of the network you're attached to:
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
    
      // print your WiFi shield's IP address:
      IPAddress ip = WiFi.localIP();
      Serial.print("IP Address: ");
      Serial.println(ip);
    
      // print the received signal strength:
      long rssi = WiFi.RSSI();
      Serial.print("signal strength (RSSI):");
      Serial.print(rssi);
      Serial.println(" dBm");
      }
    
    

    Arduino Without Shield - Upload 

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    //All the libraries used
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(A5, A4); // RX, TX
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    IPAddress stationIP = IPAddress(192, 168, 111, 112);
    IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
    IPAddress remoteIp;
    bool broadcasting = false;
    
    //WiFi network settings
    char ssid[] = "homebase";            // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    
    //Ports to be used
    unsigned int listeningPort = 10003;  // local port to listen on
    unsigned int sendingPort = 10002;  // local port to listen on
    char packetBuffer[255];          // buffer to hold incoming packet
    char ReplyBuffer[] = "ACK";      // a string to send back
    
    //Arrays for storing sent and received packets
    String message;
    char messageToSend[16];
    
    //Transmition variables
    bool waitForACK = false;
    //How many transmit attempts
    int transmits = 0;
    int transmitLimit = 2;
    unsigned long previousTransmit;
    //Time between attempts
    int interval = 1000;
    
    //States for state machine
    enum states {
      WRITING,
      RECEIVED,
      SENDING,
      SHOW,
      FAIL,
      SUCCESS
    };
    
    //Variable to keep track of states
    states currentState = WRITING;
    
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for ESP module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.configAP(apIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Make a network
        status =  WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
      }
    
      //Print WiFi status
      Serial.println("Connected to wifi");
      printWifiStatus();
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    }
    
    
    void loop() {
    
      //Check for incoming packets
      int packetSize = Udp.parsePacket();
    
      // If there are packets
      if (packetSize) {
        //Print out update
        Serial.println(F("Packets Received"));
        // read the packet into packetBufffer
        int len = Udp.read(packetBuffer, 255);
        if (len > 0) {
          packetBuffer[len] = 0;
        }
    
        //If the packets are an "ACK" message
        if (String(packetBuffer) == String(ReplyBuffer) && waitForACK) {
          // Update current state
          currentState = SUCCESS;
        }
        else {
          //If the packet are a text message
          currentState = RECEIVED;
        }
      }
    
      //Beginning of state machine
      switch (currentState) {
        // Instructions for WRITING state
        case WRITING:
          //Check to see if something was written and sent
          if (Serial.available() > 0) {
            //Store text in message
            message = Serial.readString();
            Serial.println("Sending message");
    
            //Clear buffers for message about to be sent
            memset(packetBuffer, 0, sizeof packetBuffer);
            memset(messageToSend, 0, sizeof messageToSend);
    
            //Convert String message into a char array
            message.toCharArray(messageToSend, sizeof messageToSend);
            //Reset transmit attempts
            transmits = 0;
            //Start listening for an "ACK" packet
            waitForACK = true;
            //Update state
            currentState = SENDING;
            //End of case
          }
          break;
    
        // Instructions for SENDING state
        case SENDING:
          // If transmit attempts are over the limit
          if (transmits > transmitLimit && waitForACK) {
            // Update current state
            currentState = FAIL;
          }
          // If the interval has passed from the last transmit
          if (millis() - previousTransmit > interval && waitForACK) {
            // Send message on correct port
            sendData(messageToSend, apIP, sendingPort);
          }
          //End of case
          break;
    
        // Instructions for FAIL state
        case FAIL:
          //Stop waiting for "ACK" message because we won't get it
          waitForACK = false;
          Serial.println(F("Transmit Failed"));
          // Update current state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for SUCCESS state
        case SUCCESS:
          //Stop waiting for "ACK" message because we got it
          waitForACK = false;
          Serial.println(F("ACK Received"));
          //Clear message by setting equal to nothing
          message = "";
          //Reset all char in the char arrays to 0
          memset(packetBuffer, 0, sizeof packetBuffer);
          memset(messageToSend, 0, sizeof messageToSend);
    
          // Update current state
          currentState = WRITING;
          //End of case
          break;
    
        // Instructions for RECEIVED state
        case RECEIVED:
          //Send "ACK" message
          sendData(ReplyBuffer, stationIP, sendingPort);
          Serial.println("Incoming Message");
          // Update current state
          currentState = SHOW;
          //End of case
          break;
    
        // Instructions for SHOW state
        case SHOW:
          Serial.print("Message: ");
          Serial.println(packetBuffer);
          // Update current state
          currentState = WRITING;
          //End of case
          break;
      }
    }
    
    void sendData(char mess[], IPAddress ip, int port) {
      //Toggle for extra info
      if (true) {
        Serial.println(F("Sending Packets"));
        Serial.print(F("Sending to: "));
        Serial.println(remoteIp);
        Serial.print(F("On Port:  "));
        Serial.println(sendingPort);
        Serial.print(F("Message is:  "));
        Serial.println(messageToSend);
      }
    
      //Toggle broadcasting vs direct ip to ip
      // Create temp ip variable
      IPAddress ipToUse;
      //If broadcasting is on
      if (broadcasting) {
        //Set destination ip to 0.0.0.0
        ipToUse = broadcastIP;
      } else {
        //Use other WiFi module ip
        ipToUse = ip;
      }
    
      //Update the last transmit time to now
      previousTransmit = millis();
      //Open packet to certain ip at certain port
      Udp.beginPacket(ipToUse, port);
      //Write message to packet
      Udp.write(mess);
      //End the packet
      Udp.endPacket();
      //Increase number of transmits
      transmits++;
    }
    
      void printWifiStatus() {
      // print the SSID of the network you're attached to:
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
    
      // print your WiFi shield's IP address:
      IPAddress ip = WiFi.localIP();
      Serial.print("IP Address: ");
      Serial.println(ip);
    
      // print the received signal strength:
      long rssi = WiFi.RSSI();
      Serial.print("signal strength (RSSI):");
      Serial.print(rssi);
      Serial.println(" dBm");
      }
    
    

    Observe

    Open up the Serial Monitor. When the connected Arduino is ready you will see a listening message. For the LCD equipped Arduino, it's ready when you no longer see the message Setting up WiFi on its display. To create messages, move the dial to get the letter you want then press the button. It will add that letter to the message. For a space, double click. When your message is ready to send, hold down the button and the Arduino will start trying to send the message. Back in the Serial Monitor, you should see a received message. To write one back, simply type into the Serial Monitor and press enter. The LCD Display should change to blue and tell you of an incoming message. Press the button to see the message and press again to return to the writing screen.

    Not ready yet
    Ready
    Twist to select letter
    Twist to select letter
    Press to add to message
    A typed out message
    Long press to send
    Success
    Sometimes not
    You'll see this when you have a message
    Press to see content
    Another press to clear

    Experiment

    Try changing out the dial for maybe more button or another sensor for typing. You can use this simple messaging system to send data from other projects. Like the intruder alarm or robot friend.

    Assemble the Enclosure

    Start 

    Below you can see a picture of the finished enclosure. All the sensors from Weather Station 1 are safe inside the acrylic enclosure. One 9 volt battery powers the sensors and data is sent back using the WiFi module from Weather Station 2. A cable passes through the base plate of the enclosure in order to connect to Weather Station 3 and provide rain data. Let's follow the instructions and put it together.

    The finished productThe finished product

    Modules 

    Gather the following parts to complete this project.

    Parts

    All Parts x Qty
    Small Wheel x 3
    Sensor x 1
    Arduino x 1
    Propeller x 1
    Mating x 2
    Front x 1
    Left x 1
    Roof x 1
    Back x 1
    Base x 1
    Right x 1
    Large Wheel x 1

    Foreword 

    The acrylic assembly in this kit is significantly easier to assemble than the one found in Weather Station 3. It will still need hot glue and some time to put together.

    Pieces 

    There are 12 unique acrylic pieces with some copies that total to 15 acrylics pieces in the kit. Remove all the pieces from the kit box and lay them out. Take off the protective covering for each piece. They are designed to fit without it on.

    The base
    Start peeling
    Keep going
    Almost there
    One side done
    Flip
    Repeat

    Walls

    We are going to start with the 4 walls of the enclosure. Grab the Front, Left, Right, and Back pieces. The Front, Left, Right, and Back pieces all have a hook at the bottom. The hook should be in this _| orientation. If it isn't, then you have the wrong side of the piece facing you. Starting with the Front and Left pieces, snap the finger jointed sides at 90 degree or right angles to each other. Repeat this for the Right piece as well. Lay the Front face down and snap the Back piece into the sides. Take a moment to check the hook positioning. They should all be facing the same way as you rotate the assembly.

    All pieces
    Check out the hook orientation
    Just Front and Left
    Align
    And snap
    Now the Right
    Align
    And snap
    Now the Back
    Align and snap
    A snapped joint
    Make sure all hooks point the same way
    Make sure all hooks point the same way
    Make sure all hooks point the same way
    Make sure all hooks point the same way
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside

    Roof

    Take the Roof pieces. There are two holes on the Roof piece that should be closer to the top than the bottom. Place the Roof piece of the remaining finger joints found on top of the walls. With the Roof in place, glue the inside joints where a wall meets a wall and where the Roof meets a wall. On the outside of the assembly, glue the seam between the Roof and Back pieces. As well as the seam between the Roof and Front pieces. Allow time for the glue to set and dry.

    Roof
    These holes
    Are closer to the top
    Line up
    Align
    Not pressed enough
    Good
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Glue all joints from inside
    Ready for next step

    Louvers

    The Louvers slot into the holes in the Front and Back pieces. The fins should be slanted down and none of the mesh underside should be visible when looking down. Use a piece of tape to secure the Louvers in place, then apply glue inside where the Louver meets the Front and Back. Allow time for the glue to set and dry.

    Louvers
    This mesh
    Should be facing down
    Press into box
    Glue from inside
    Glue from inside
    Glue from inside
    Take the remaining louver
    Place into box
    Glue from inside
    Glue from inside
    Glue from inside

    Propeller Latch and Base

    Take the Mating pieces and slot them together to create an X. Place one Small Wheel all the way down the X. Next goes the Propeller piece, then another Small Wheel. Take the Base piece and place it on the X so the Small Wheel, that was just put on, fits in the hole in the middle of the Base piece. Add the Large Wheel and then the last Small Wheel. The pieces should be tight enough to stay together but not so tight as to impede the movement of the propeller latch. There should be some extra space on the X. This will be used later.

    The two Mating pieces
    Tilt
    Slide together
    They make an X
    They make an X
    Take a Small Wheel
    Place on the X
    Take the Propeller
    Line up
    Slide to bottom
    Take another Small Wheel
    Line up
    Slide down to bottom
    Take the Base
    Line up
    Place so it fits in the hole in the middle
    Base and Small Wheel are one layer
    Take the Large Wheel
    Line up
    Slide down
    Take the last Small Wheel
    Line up
    Slide down

    Test Fit

    Turn the Propeller so that the spokes don't overhang from the Base piece. Slide the slots in the Base piece over the hooks in the Front, Left, Right, and Back pieces. Twisting the Propeller piece will slide the spokes under the hooks and friction seal the enclosure.

    Turn so the spokes
    Are like this
    Place the base onto the hooks
    Place the base onto the hooks
    Twist Propeller
    Twist Propeller
    Close up
    Close up
    Locked
    Unlocked
    And remove
    and remove

    Great Job 

    With the initial construction of the enclosure done we can update the weather sensor code. It's easier to do this outside of the enclosure. You should have some extra acrylic pieces. Keep those near by as we'll need them later.

    Assemble the Sensor Mount

    Start 

    Below you can see the finished mount installed in the enclosure we just made. This sensor mount allows for air flow as well as some cable management as to not interfere with the sunlight sensor.

    The Sensor MountThe Sensor Mount

    Modules 

    These are the parts inside the bag of hardware and what we'll need for this section.

    Parts

    All Parts x Qty
    38mm Nylon Standoffs x 2
    6mm Nylon Screws x 2
    10mm Nylon Screws x 3
    Nylon Nuts x 5
    Sensor Acrylic Part x 1
    Arduino Acrylic Part x 1
    BME280 x 1
    Sunlight Sensor x 1
    WiFi Module x 1
    1x1 Wrapper x 1
    2x1 Wrapper x 2

    Attaching the Arduino 

    Grab an Arduino without the base shield, Arduino part, all 3 10mm screws, and 3 nuts. The three holes in the Arduino will match up to the holes on the Arduino piece. Place the Arduino on top then add a screw to any hole. Push it through before flipping it over and attaching a nut. Don't fully tighten the nut at this time. Repeat with the other 2 holes and screw. The screw near the Arduino headers will go in diagonal and not fully down. This is okay. With all three screws and nuts attached, you can now tighten all of them.

    All the parts
    The holes in the piece
    The holes in the Arduino
    Take the Arduino
    And line up the holes
    Take one screw
    Place into the hole
    Flip over and get a nut
    Lightly tighten the nut
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Repeat for the other holes
    Fully tighten the remaining nuts
    Fully tighten the remaining nuts

    Attaching the Base Shield 

    Grab the base shield, both standoffs, and the remaining nuts. Take a standoff and place the threaded side through one of the mounting holes in the base shield. The standoff should be pointing up like the sockets do. Flip it over the shield and tighten down a nut. Repeat this for the other standoff and nut. Then place the shield onto the Arduino.

    All the parts
    The mounting holes
    Take a standoff
    Place into mounting hole
    Standoff pointing up
    Flip over
    Take a nut
    Tighten to threads
    Flip over
    Add the other standoff
    Flip over
    Grab remaining nut
    Tighten to threads
    Shield and Arduino
    Connected
    Ready

    Sensor Mount 

    Grab the Sensor piece, all the sensors, all the wrappers, both 6mm screws, as well as 3 long screws and 3 metal hex nuts that come with your wrappers. Click your wrappers together like seen in the picture. Place the 3 part wrapper on top of the Sensor piece. Line up the smaller holes on the short sides of the wrappers with the holes in the Sensor piece. Drop in a hex nut where there are cutouts in the wrapper. We only need the ones that have holes in the Sensor piece. Flip over and screw in a screw to each of the holes. With all three tightened we can snap in the sensors.

    All the parts
    Wrappers and hex nuts
    Holes and screws
    Other two screws
    Grab wrapper
    Place on sensor plate
    Line up with these holes
    Line up with these holes
    Line up with these holes
    Add nuts
    Add screw
    Hand tighten
    So it threads
    Add another screw
    Hand tighten or
    Use a screwdriver
    Till it treads all the way
    Repeat for last one
    Repeat for last one
    Repeat for last one
    Repeat for last one
    All screws in
    Click sensors in
    Click sensors in
    Click sensors in
    Click sensors in
    Click sensors in
    Click sensors in

    Mount to Shield 

    The two bigger holes in the Sensor mount are for the shield. Line it up and screw in the 2 remaining nylon screws. The mount in complete.

    Where the screws go
    Line up mount
    Take a screw
    Tread in
    Finish with screwdriver
    Take the other screw
    Thread in
    Finish with screwdriver
    Finished mount
    Finished mount
    With sensors

    Wire it Up 

    Now we'll need our cables. Take a cable. Unwrap it and attach one side to the BME280 socket. The other goes to any I2C socket. Take a cable. Unwrap it and attach one side to the sunlight socket. The other goes to any I2C socket. Take a cable. Unwrap it and attach one side to the WiFi Module. The other goes to the D8 socket.

    All the parts
    Take a cable
    Unwrap it
    Attach one side to the BME280 socket
    The other goes to any I2C socket
    The other goes to any I2C socket
    Take a cable
    Unwrap it
    Attach one side to the sunlight socket
    The other goes to any I2C socket
    The other goes to any I2C socket
    Take a cable
    Unwrap it
    Attach one side to the WiFi Module
    The other goes to the D8 socket
    The other goes to the D8 socket
    Ready to go!

    Next Section 

    In the last section of assembly, we will install the two components we've built.

    Installing the Sensors

    Start 

    We will now add the two components together to make the finished Weather Station. Check it out below.

    Looking good!Looking good!

    Sensors In 

    Take your sensor mount and check out the X on the underside. This should match up to the X in the enclosure part. With it lined up, press down to connect both pieces. The mount can now be sealed into the enclosure by using the propeller latch.

    Base and mount
    X on the mount
    X on the base
    Together
    Check it out
    In the enclosure
    Cool!
    Software and Final Steps

    Start 

    Let's upload some code and attached the rain gauge.

    Code 

    With the base unlatched we can easily upload code. Upload the following code. It's the same one from Weather Station 3 but the magnet socket is changed from D5 to D2. You'll see why later. Remember to add in your network details as well as your Wunderground ID and key.

    Base off
    Code on
    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    #include "WiFiEsp.h"
    #include <Wire.h>
    #include "Seeed_BME280.h"
    #include <math.h>
    #include "Arduino.h"
    #include "SI114X.h"
    #include "SoftwareSerial.h"
    #include <OneButton.h>
    
    #define magSocket 2
    
    //Defines for Wunderground variables
    #define WID "WUNDERGROUND_ID"
    #define WKEY "WUNDERGOUND_KEY"
    #define getPayload "/weatherstation/updateweatherstation.php?ID="  WID  "&PASSWORD="  WKEY  "&dateutc=now&tempf=%s&humidity=%s&baromin=%s&UV=%s&dailyrainin=%s&action=updateraw"
    
    
    //Create serial communication object
    SoftwareSerial Serial1(8, 9); // RX, TX
    
    //Wifi settings
    char ssid[] = "YOURWIFINETOWRK";       // your network SSID (name)
    char pass[] = "YOURPASSWORD";      // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    //Server URL for later
    char server[] = "weatherstation.wunderground.com";
    
    //Storage for getPayload
    char buf[200];
    
    
    // Initialize the Ethernet client object
    WiFiEspClient client;
    
    // Construct sensor objects
    SI114X sunlightSensor;
    BME280 bme280;
    
    //Attach magnet switch to one button
    OneButton magSwitch(magSocket, true);
    
    // Variables for weather measurements
    float temperature;
    float humidity;
    float pressure;
    float uv;
    float rain;
    
    // Letter version of the variables from above
    char cTemp[8];
    char cHum[8];
    char cPress[8];
    char cUv[8];
    char cRain[8];
    
    // Variable to hold time
    unsigned long previousMillis = 0;
    unsigned long newDayMillis = 0;
    
    // Milliseconds to wait between updates.
    const long interval = 2 * 60 * 1000L;
    const long dayMillis = 86400000L;
    
    void setup() {
      // Initialize serial for debugging
      Serial.begin(9600);
      // Initialize serial for ESP module
      Serial1.begin(9600);
      // Initialize ESP module
      WiFi.init(&Serial1);
    
      // Initialize sunlight sensor
      while (!sunlightSensor.Begin()) {
        Serial.println(F("Sunlight Error"));
        delay(1000);
      }
    
      // Initialize BME280 sensor
      if (!bme280.init()) {
        Serial.println(F("BME Error"));
      }
    
      // Attempt to connect to WiFi network
      while (status != WL_CONNECTED) {
        Serial.print(F("Attempting to connect to WPA SSID: "));
        Serial.println(ssid);
        // Connect to WPA/WPA2 network
        status = WiFi.begin(ssid, pass);
      }
    
      // You're connected now, so print out the data
      Serial.println(F("You're connected to the network"));
    
      // Print out all info about wifi connection
      printWifiStatus();
    
      // Run updateWeather function
      updateWeather();
      // Run sendData function
      sendData();
    
      //Create magnet switch function
      magSwitch.attachClick(bucketMove);
    }
    
    void loop() {
      // Store the current time
      unsigned long currentMillis = millis();
    
      // Check to see if enough time has passed
      if (currentMillis - previousMillis >= interval) {
        // Save the last time data was sent
        previousMillis = currentMillis;
    
        //Check to see if a day has passed
        if (currentMillis - newDayMillis >= dayMillis ){
          //Set rain measured to 0
          rain = 0;
          //Reset day counter
          newDayMillis = currentMillis;
        }
    
        // Run updateWeather function
        updateWeather();
        // Run sendData function
        sendData();
      }
    
      //Listen for rain events
      magSwitch.tick();
    
      // While there is a connection to the server
      while (client.available()) {
        // Store the response
        char c = client.read();
        // And print it to the serial console
        Serial.write(c);
      }
    
      // If the server's disconnected, stop the client:
      if (!client.connected()) {
        // Prints debugging messages
        //Serial.println();
        //Serial.println("disconnecting from server.");
        // Disconnect the server
        client.flush();
        client.stop();
      }
    }
    
    void updateWeather() {
      // Read temp and convert to F
      temperature = bme280.getTemperature();
      temperature = temperature * 1.8 + 32;
    
      // Read humidity
      humidity = bme280.getHumidity();
    
      // Read Pressure and convert to inches of water
      pressure = bme280.getPressure() * 0.00040146;
    
      // Read UV and convert to UV Index range
      uv = (float)sunlightSensor.ReadUV() / 100;
    
      // Calculate rain in inches. See tutorial on why it's .09
      rain = rain * .09;
    }
    
    void sendData() {
      // Convert float numbers to char arrays
      dtostrf(temperature, 4, 2, cTemp);
      dtostrf(humidity, 4, 2, cHum);
      dtostrf(pressure, 4, 2, cPress);
      dtostrf(uv, 4, 2, cUv);
      dtostrf(rain, 4, 2, cRain);
    
      // Try and send the data
      if (client.connect(server, 80)) {
        // Make a HTTP request:
        sprintf(buf, getPayload, cTemp, cHum, cPress, cRain, cUv);
        client.println(String("GET ") + buf + String(" HTTP/1.1"));
        //Serial.println(String("GET ") + buf + String(" HTTP/1.1"));
        client.println(F("Host: weatherstation.wunderground.com"));
        client.println(F("Connection: close"));
        client.println();
      }
    
    }
    void printWifiStatus()
    {
      // Print the SSID of the network you're attached to
      Serial.print(F("SSID: "));
      Serial.println(WiFi.SSID());
    
      // Print your WiFi shield's IP address
      IPAddress ip = WiFi.localIP();
      Serial.print(F("IP Address: "));
      Serial.println(ip);
    
      // Print the received signal strength
      long rssi = WiFi.RSSI();
      Serial.print(F("Signal strength (RSSI):"));
      Serial.print(rssi);
      Serial.println(F(" dBm"));
    }
    
    void bucketMove() {
      //Increment the rain detected
      rain++;
    }
    
    

    Battery Powered 

    I'm going to put a battery in here to use it fully wirelessly. I did have to bend the cable a bit. The side with the barrel jack. It's better to do this when it isn't inside the Arduino.

    USB out
    Battery in
    A good place for the battery
    Back in the enclosure
    Twisted shut

    Rain Gauge 

    There is one opening in the enclosure and that is for the rain gauge from Weather Station 3. Using the long cable, plug one side in the magnet switch socket. The other through the hole in the bottom and into D2. The base can be latched and now go get some weather data!

    Base and gauge
    Here is the hole
    Plug into the switch
    Through the hole
    Pull a bit
    Into D2
    Into D2
    All done!

    There is a more to this kit 

    We added the other Arduino so you could have one outside with the Weather Station and the other would be inside with the LCD Display relaying the data. We'd like you to build this version first to make sure everything is working. The next section will release a week after this one shipped. It will just be a software update and another project using parts you have. Get hyped!

    Wireless Robot Friend

    Waving from a far 

    With this modification you can have your robot friend from the Creator Set react to stimulus from far away.

    Modules 

    Gather the following parts to complete this project.

    Parts

    All Parts x Qty
    Arduino with Base Shield x 1
    Ardunio Without Base Shield x 1
    WiFi Module x 2
    Servo x 1
    Potentiometer x 1
    Cables x 3

    Robot Side Assembly 

    This part will use the Arduino without the base shield. We are going upload code first then add the components. We are using the UART socket so programming must be done first.

    Robot parts
    Take USB
    Plug in

    Upload

    Uploading the following code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    //All the libraries used
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    #include <Servo.h>
    
    //Change here if you're using a different socket
    #define servoSocket A5 //<- digital socket number
    
    //Create a Servo object
    Servo robotArm;
    
    //Variable for received dervo position
    int pos;
    
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    IPAddress stationIP = IPAddress(192, 168, 111, 112);
    IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
    IPAddress remoteIp;
    bool broadcasting = false;
    
    //WiFi network settings
    char ssid[] = "robotRec";            // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    
    //Ports to be used
    unsigned int listeningPort = 10002;  // local port to listen on
    unsigned int sendingPort = 10003;  // local port to listen on
    char packetBuffer[255];          // buffer to hold incoming packet
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
    
      // Connect serial to Wifi module
      WiFi.init(&Serial);
      WiFi.configAP(apIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Make a network
        status =  WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
      }
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    
      //Attach servo object to servo socket
      robotArm.attach(servoSocket);
    }
    
    void loop() {
      // if there's data available, read a packet
      int packetSize = Udp.parsePacket();
      if (packetSize) {
        // read the packet into packetBufffer
        int len = Udp.read(packetBuffer, 255);
        if (len > 0) {
          packetBuffer[len] = 0;
        }
    
        //Convert received data to an int
        pos = atoi(packetBuffer);
      }
    
      //Tell Servo to move to received position
      robotArm.write(pos);
    }
    

    Adding the components

    Unwrap a cable and connect one end to a WiFi Module and the other end to the UART socket on the Arduino. Plug the servo to either I2C Socket.

    Unplug
    Take a cable
    Unwrap it
    Connect one end to a WiFi Module
    The other end to the UART socket
    Take the Servo
    Connect to either I2C socket
    Ready for the Controller

    Control Side Assembly 

    This part doesn't use the UART socket so it can be put together normally. Unwrap a cable and connect one end to the unused WiFi module and the other to the D8 socket. Unwrap another cable and plug one end into the Potentiometer socket with the other going into the A0 socket.

    All the parts
    Take a cable
    Unwrap it
    Plug one end to the WiFi Module
    The other to the D8 socket
    Take the other cable
    Unwrap it
    Plug into the Potentiometer socket
    the other into A0

    Upload

    Upload the following code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    //All the libraries used
    #include <WiFiEsp.h>
    #include <WiFiEspUdp.h>
    #include "SoftwareSerial.h"
    
    //Change here if you're using a different socket
    #define dialSocket A0//<- analog socket number
    
    //Variables for store dial position
    int pos;
    int val;
    
    //Char array for sending position data
    char posData[8];
    
    //Socket of the WiFi module
    SoftwareSerial Serial1(8, 9); // RX, TX
    //Create UDP object
    WiFiEspUDP Udp;
    
    //IP and broadcasting varibles
    IPAddress apIP = IPAddress(192, 168, 111, 111);
    IPAddress stationIP = IPAddress(192, 168, 111, 112);
    IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
    IPAddress remoteIp;
    bool broadcasting = false;
    
    //WiFi network settings
    char ssid[] = "robotRec";            // your network SSID (name)
    char pass[] = "password";        // your network password
    int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
    //Ports to be used
    unsigned int listeningPort = 10003;  // local port to listen on
    unsigned int sendingPort = 10002;  // local port to listen on
    
    void setup() {
      // initialize serial for debugging
      Serial.begin(9600);
      // initialize serial for ESP module
      Serial1.begin(9600);
      // Connect serial to Wifi module
      WiFi.init(&Serial1);
      WiFi.config(stationIP);
    
      // attempt to connect to WiFi network
      while ( status != WL_CONNECTED) {
        // Print which SSID it's trying to connect to
        Serial.print(F("Attempting to connect to WPA SSID: "));
        Serial.println(ssid);
        // Connect to WPA/WPA2 network
        status = WiFi.begin(ssid, pass);
      }
    
      // Set up UDP listener on port
      Udp.begin(listeningPort);
    
      // Print out which port
      Serial.print(F("Listening on port "));
      Serial.println(listeningPort);
    }
    
    
    void loop() {
      //Read dial voltage
      val = analogRead(dialSocket);
    
      //Convert reading to degree
      pos = map(val, 0, 1024, 0, 180);
    
      //Store degrees in char array
      sprintf (posData, "%03i", pos);
      Serial.println(posData);
    
      //Open packet to certain ip at certain port
      Udp.beginPacket(broadcastIP, sendingPort);
      //Write message to packet
      Udp.write(posData);
      //End the packet
      Udp.endPacket();
    }
    

    Info

    You must have both Arduinos powered for this to work.

    Observe

    The sending Arduino will connect to a network made by the receiving Arduino. Once connected it will send updated dial position data. The other Arduino receives this and drives the servo.

    My set up
    This dial control the servo
    These two are connected via WiFi
    Turn this to move the servo
    Turn this to move the servo

    Modify

    The Potentiometer can be swapped with any sensor such as light or sound.