Project

Make an Automatic Water Softener Reporter

August 20, 2015 by Travis Fagerness

Create a smart home by displaying the current salt level of your water softener with the CC3200 and a proximity sensor.

Create a smart home by displaying the current salt level of your water softener with the CC3200 and a proximity sensor.

Recommended Level

Intermediate

Requirements

  • CC3200 Demo board
    • Updated to latest firmware for Energia support, directions here.
  • Energia - Arduino IDE Clone from TI
    • Use in article: v. 0101E00016
  • Proximity Sensor
  • Jumper wires, soldering wires or JST 3 terminal with wires
  • 2 - 10kohm resistors
    • This is needed because the ADC on the CC3200 can only read values up to 1.46V.
  • Dweet.io "thing"

Hardware Setup

Connecting the wires

CC3200 pinout here.

 CC3200    Proximity Sensor
 Pin 21 -- 5V Power    Pin 3 -- VCC
 Pin 22 -- GND    Pin 2 -- GND
 Pin 24 -- ADC <-- through voltage divider -->  Pin 1 -- Vo

Testing the connection and measuring calibration values

The code below samples the proximity sensor output and converts it to a distance. 

  1. Copy the code below into a new sketch.
  2. Select the correct board in Tools>Board>Launchpad w/ CC3200 80MHz.
  3. Program the board.
    1. File>Upload or the arrow button
  4. Open the terminal, Ctrl+Shift+M, and you will see the distance printed once every 200ms.
  5. Move a solid surface near the sensor to see the number change. See video below for an example. If the distance is outside of the measurement range, incorrect values can be displayed.
  6. To calibrate the sensor for you water softener, mount the sensor where you intend to place it inside the softener. I mounted mine temporarily with tape. For a permament solution, you would want to use screws or glue, ideally in a project case.
  7. Remove salt until it is at a level you want the sensor to show 0%.
    1. Make note of the raw data value being reported.
  8. Put a handful of salt in your hand and move it towards the sensor where you want to show 100%.
    1. Make note of the raw data value being reported.

Demonstration of the proximity sensor test code

The following video shows step 5 of the instructions above.

/*Take a proximity measurement and send out over the serial port*/
#define PROX_PIN  24
float prox_sensor_value_V = 0;
float distance_cm = 0;
/*values from datasheet for sensor*/
#define MAX_SENSOR_VOLTAGE 2.8
#define MIN_SENSOR_VOLTAGE 0.4
#define MAX_SENSOR_DISTANCE_CM  150
#define MIN_SENSOR_DISTANCE_CM  15
void setup()
{
  Serial.begin(115200);
}

void loop()
{
  prox_sensor_value_V = (float)analogRead(PROX_PIN) *2*  1.46 / 4096;
  if(prox_sensor_value_V>=2.8 && prox_sensor_value_V <= 0.4){
    Serial.println("Sensor out of range, object must be 15-150cm");
  }
  else{
    /*convert to distance
    * linearly convert based on the inverse relationship between voltage and distance
    * described in the datasheet
    *
    * Could get more precision by doing a calibration and using a look-up table
    */
    distance_cm = (prox_sensor_value_V - MIN_SENSOR_VOLTAGE) * \
    (MIN_SENSOR_DISTANCE_CM - MAX_SENSOR_DISTANCE_CM)\
    / (MAX_SENSOR_VOLTAGE - MIN_SENSOR_VOLTAGE) + MAX_SENSOR_DISTANCE_CM;
    
    Serial.print("Distance: ");
    Serial.print(distance_cm,1);
    Serial.print("cm -- ");
    Serial.print(distance_cm/2.2,1);
    Serial.println("in");
  }
  delay(200);
}

water2.zip

Setup dweet.io

dweet.io

  1. Go to https://dweet.io/play/
  2. Click "Create a dweet for a thing"
  3. Fill in the parameters for the thing and the content. Choose a thing name that is very unique unless you plan to pay for a "locked" thing, otherwise people can easily view it or change it. We want to display the water softener percent_level, so that is the content. It must be a valid JSON string.
  4. Click "Try it out!" to see what will happen when posting to the dweet. The request URL is what we'll use to post from the CC3200.

Post to dweet.io from the CC3200

The following code will connect to the dweet.io setup in the previous setup and post the percent value of the water softener. It works by opening a connection to the HTTP server of dweet.io on port 80 and requesting the webpage using the GET function. This is the same as pasting the URL in the previous section into a web browser to write a value. 

  1. Copy the code below into a new sketch.
  2. Select the correct board in Tools>Board>Launchpad w/ CC3200 80MHz.
  3. Modify the following variables to your settings:
    Variable Description
    ssid The SSID of your Wifi network
    password The password to your Wifi network
    thing The name of the thing created in the previous section
    distance_cm_0percent Distance that you want to equate to 0% salt level
    distance_cm_100percent Distance that you want to equate to 100% salt level
  4. Program the board.
  5. File>Upload or the arrow button.
  6. Open the terminal, Ctrl+Shift+M, and you will see the salt level uploaded once a second.
  7. Wave your hand near the sensor to see the number change and view realtime at the URL of your thing.
    1. This article uses https://dweet.io:443/get/latest/dweet/for/my_water_softener
    2. Here is the output:
      {"this":"succeeded","by":"getting","the":"dweets","with":[{"thing":"my_water_softener","created":"2015-08-14T02:40:59.181Z","content":{"percent_level":21}}]}
  8. The website isn't very user friendly, but does indicate the percent level from anywhere with internet access. Some other options for displaying data:
    1. Using freeboard.io
      1. This option requires an account.
    2. Paying for a "lock" to send an alert based on the value on dweet.io.
      1. This is useful if you want an email when the salt percetage is below a certain level.
    3. Create your own webpage to create a plot using all of the JSON data from the dweet.
      1. This option is similar to creating a webpage using Google Chart.

        .
#include 
#include 

/*user defined settings*/
#define PROX_PIN  24
char ssid[] = "ssid";                 //SSID of network
char password[] = "password";           //password for wireless network
char thing[] = "thing";      //dweet thing
int distance_cm_0percent = 15;           //distance that you want to show 0%
int distance_cm_100percent = 140;         //distance that you want to show 100%

/*variables*/
float prox_sensor_value_V = 0;
float distance_cm = 0;
uint8_t salt_level_percent = 0;
WiFiClient client;

/*values from datasheet for sensor*/
#define MAX_SENSOR_VOLTAGE 2.8
#define MIN_SENSOR_VOLTAGE 0.4
#define MAX_SENSOR_DISTANCE_CM  150
#define MIN_SENSOR_DISTANCE_CM  15

void setup()
{
  Serial.begin(115200);
   Serial.print("Attempting to connect to Network named: ");
  Serial.println(ssid); 
  /*Connect to WPA/WPA2 network. Change this line if using open or WEP network*/
  WiFi.begin(ssid, password);
  while ( WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("\nYou're connected to the network");
  
  Serial.println("Waiting for an ip address");
  while (WiFi.localIP() == INADDR_NONE) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("\nIP Address obtained");
  printWifiStatus();
}

void loop()
{
  prox_sensor_value_V = (float)analogRead(PROX_PIN) *2*  1.46 / 4096;
  if(prox_sensor_value_V>=2.8 && prox_sensor_value_V <= 0.4){
    Serial.println("Sensor out of range, object must be 15-150cm");
  }
  else{
    /*convert to distance
    * linearly convert based on the inverse relationship between voltage and distance
    * described in the datasheet
    *
    * Could get more precision by doing a calibration and using a look-up table
    */
    distance_cm = (prox_sensor_value_V - MIN_SENSOR_VOLTAGE) * \
    (MIN_SENSOR_DISTANCE_CM - MAX_SENSOR_DISTANCE_CM)\
    / (MAX_SENSOR_VOLTAGE - MIN_SENSOR_VOLTAGE) + MAX_SENSOR_DISTANCE_CM;
    Serial.print("Distance: ");
    Serial.print(distance_cm,1);
    Serial.print("cm -- ");
    Serial.print(distance_cm/2.2,1);
    Serial.println("in");
    /*convert to calibrated values and cap at max value*/
    if(distance_cm > distance_cm_100percent) distance_cm=distance_cm_100percent;
    if(distance_cm < distance_cm_0percent) distance_cm=distance_cm_0percent;
    salt_level_percent = map((int)distance_cm,distance_cm_0percent,distance_cm_100percent,100,0);
    Serial.print("Salt level percent: ");
    Serial.print(salt_level_percent);
    Serial.println("%");
    /*Send to dweet.io server using HTTP GET function, equivalent to typing the webpage into your browser*/
    Serial.println("Send to dweet.io");
    if (client.connect("www.dweet.io", 80)) {
      client.print("GET /dweet/for/");
      client.print(thing);
      client.print("?percent_level=");
      client.print(salt_level_percent);
      client.println(" HTTP/1.1");
      
      client.println("Host: dweet.io");
      client.println("Connection: close");
      client.println("");
      
      /*print the response from the server for debug purposes*/
      while (client.connected()) {
        while (client.available()) {
          Serial.write(client.read());
        }
      }
      Serial.println("");
    }
    else{
      Serial.println("Error: Coult not connect to dweet server!");
    }
  }
  delay(60000);
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi 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");
}


water.zip

Give this project a try for yourself! Get the BOM.

2 Comments
  • T
    texasclodhopper August 27, 2015

    I’d be really surprised if your electronics didn’t suffer some adverse affects from being in the same closed environment with all that “salt.”

    Like. Reply
  • B
    bgwiz March 03, 2016

    @texasclodhopper I agree.  Living in MN, we watch cars slowly get ‘eaten’ by the salt used in the winter.

    Just keep everything except the proximity sensor far away and all should be good as long as the sensor is sealed well.

     

    Like. Reply