MultiLevelSensor and OnOffSwitch

This is my first foray into the Gateway - I am trying to set up an irrigation system for multiple planters using Arduinos and ESP83266s from Adafruit. I have seen an example of a MultiLevelSensor and one for OnOffSwitch but none have both. And it seems that each one uses different sets of libraries which has made understanding difficult.

When I run this code, I can see from the serial monitor that it comes online and is receiving moisture readings from the Arduino, but the Gateway can’t find it - even if I enter the URL.

#include <Arduino.h>
#include <Thing.h>
#include <WebThingAdapter.h>

const char* ssid = “xxxxxxx”;
const char* password = “xxxxx”;

const int valvePin = 13;
const int PinA = 12;
const int PinB = 14;
const int PinC = 16;
int MDSIndex = 0;

boolean newData = false;

String mDNSHostname = “”;
String URLAbbrev = “”;

WebThingAdapter *adapter = NULL;

const char *deviceTypes[] = {“MultiLevelSensor”, “OnOffSwitch”, nullptr};

ThingDevice MultiLevelSensor(“Soil Moisture”, “Moisture Sensor”, deviceTypes);
ThingDevice OnOffSwitch(“Valve”, “Valve”, deviceTypes);

ThingProperty LevelProperty(“Soil Moisture Sensor”, “SensorX”, NUMBER, “LevelProperty”);
ThingProperty valveOn(“Water On”, “ValvePin”, BOOLEAN, “OnOffProperty”);

int moistLevel = 0;

const byte numChars = 4;
char receivedChars[numChars]; // an array to store the received data

String DNSName[] = {“BlueberryWest”, “BlueberryCenter”, “BlueberryEast”, “LowWest”, “HighWest”, “HighEast”, “LowEast”};

String URLName[] = {"/BBW/", “/BBC/”, “/BBE/”, “/LPW/”, “/HPW/”, “/HPE/”, “/LPE/”};

void setup() {
pinMode(valvePin, OUTPUT);
Serial.begin(115200);
MDSIndex = determineAddress(); // Address set by DIP switches on pins 12, 14, 16
mDNSHostname = DNSName[MDSIndex];
URLAbbrev = URLName[MDSIndex];

Serial.println(" “);
Serial.println(MDSIndex);
Serial.print(mDNSHostname);
Serial.print(” ");
Serial.println(URLAbbrev);

// Connect to WiFi access point
Serial.print(“Connecting to “);
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(”.”);
}

// Show connection details
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: “);
Serial.println(WiFi.localIP());
Serial.println(” ");

// Create new WebThings connection handle (default port: 80)
adapter = new WebThingAdapter(mDNSHostname, WiFi.localIP());

// Associate device with connection
MultiLevelSensor.addProperty(&LevelProperty);
adapter->addDevice(&MultiLevelSensor);
OnOffSwitch.addProperty(&valveOn);
adapter->addDevice(&OnOffSwitch);

// Start mDNS and HTTP server
adapter->begin();
Serial.println(“HTTP server started”);
Serial.print(“http://”);
Serial.print(WiFi.localIP());
Serial.print(URLAbbrev);
Serial.println(MultiLevelSensor.id);

// set initial values

ThingPropertyValue initialOn = {.boolean = false};
valveOn.setValue(initialOn);
(void)valveOn.changedValueOrNull();
digitalWrite(valvePin, LOW);
}

void loop() {

recvWithEndMarker();
showNewData();

ThingPropertyValue MVal;
MVal.number = moistLevel;
LevelProperty.setValue(MVal);
adapter->update();

bool on = valveOn.getValue().boolean;
if (on) {
Serial.println(“On”);
digitalWrite(valvePin, HIGH );
} else {
Serial.println(“Off”);
digitalWrite(valvePin, LOW);
}
delay(1000);
}

void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = ‘\n’;
char rc;

while (Serial.available() > 0 && newData == false) {
rc = Serial.read();

if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = ‘\0’; // terminate the string
ndx = 0;
newData = true;
}
}
}

void showNewData() {
if (newData == true) {
String l = receivedChars;
moistLevel = l.toInt();
Serial.println(moistLevel);
newData = false;
}
}

I suspect that my error(s) lie in how I have defined the device, but I’m stuck. Do I need another type array for the OnOffSwitch? Or is that set up correctly? Any input will be appreciated

I’m trying to build and test your example, but where does determineAddress() come from?

I have the function is in a separate file.
If you comment out
MDSIndex = determineAddress();

It will will default to the initial value 0 or use this code

int determineAddress()
{
pinMode(PinA, INPUT_PULLUP); // pin 12
pinMode(PinB, INPUT_PULLUP); // pin 14
pinMode(PinC, INPUT_PULLUP); // pin 16

int val= 0;
int total = 0;
val = digitalRead(PinA);
if(val== LOW) total = total + 1;
val = digitalRead(PinB);
if(val== LOW) total = total + 2;
val = digitalRead(PinC);
if(val== LOW) total = total + 3; // Max 7 in array

return(total);
}

Ok, you were really close! A couple small changes:

  1. You need to enable the LARGE_JSON_BUFFERS option, documented here.
  2. Since you’re creating two separate devices, you should only add the appropriate capabilities to each device, i.e. one device should be "MultiLevelSensor", while the other should be "OnOffSwitch". If, instead, you add both properties to a single device, that device would then have both capabilities.
  3. I added some additional details to your level property, which requires a minimum and maximum, at the least. The schemas are documented here.
#define LARGE_JSON_BUFFERS 1

#include <Arduino.h>
#include "Thing.h"
#include "WebThingAdapter.h"

const char* ssid = "xxxxxxx";
const char* password = "xxxxx";

const int valvePin = 13;
const int PinA = 12;
const int PinB = 14;
const int PinC = 16;
int MDSIndex = 0;

boolean newData = false;

String mDNSHostname = "";
String URLAbbrev = "";

WebThingAdapter *adapter = NULL;

const char *sensorDeviceTypes[] = {"MultiLevelSensor", nullptr};
ThingDevice MultiLevelSensor("device:esp8266:moisture", "Soil Moisture Sensor", sensorDeviceTypes);
ThingProperty moistureLevel("moistureLevel", "SensorX", NUMBER, "LevelProperty");

const char *switchDeviceTypes[] = {"OnOffSwitch", nullptr};
ThingDevice OnOffSwitch("device:esp8266:valve", "Valve", switchDeviceTypes);
ThingProperty valveOn("valveOn", "ValvePin", BOOLEAN, "OnOffProperty");

int moistLevel = 0;

const byte numChars = 4;
char receivedChars[numChars]; // an array to store the received data

String DNSName[] = {"BlueberryWest", "BlueberryCenter", "BlueberryEast", "LowWest", "HighWest", "HighEast", "LowEast"};

String URLName[] = {"/BBW/", "/BBC/", "/BBE/", "/LPW/", "/HPW/", "/HPE/", "/LPE/"};

void setup() {
    pinMode(valvePin, OUTPUT);
    Serial.begin(115200);
    //MDSIndex = determineAddress(); // Address set by DIP switches on pins 12, 14, 16
    mDNSHostname = DNSName[MDSIndex];
    URLAbbrev = URLName[MDSIndex];

    Serial.println(" ");
    Serial.println(MDSIndex);
    Serial.print(mDNSHostname);
    Serial.print(" ");
    Serial.println(URLAbbrev);

    // Connect to WiFi access point
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while ( WiFi.status() != WL_CONNECTED ) {
        delay(500);
        Serial.print(".");
    }

    // Show connection details
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println(" ");

    // Create new WebThings connection handle (default port: 80)
    adapter = new WebThingAdapter(mDNSHostname, WiFi.localIP());

    // Set up property details
    moistureLevel.title = "Moisture Level";
    moistureLevel.minimum = 0;
    moistureLevel.maximum = 100;
    moistureLevel.unit = "percent";
    valveOn.title = "On";

    // Associate device with connection
    MultiLevelSensor.addProperty(&moistureLevel);
    adapter->addDevice(&MultiLevelSensor);

    OnOffSwitch.addProperty(&valveOn);
    adapter->addDevice(&OnOffSwitch);

    // Start mDNS and HTTP server
    adapter->begin();
    Serial.println("HTTP server started");
    Serial.print("http://");
    Serial.print(WiFi.localIP());
    Serial.print(URLAbbrev);
    Serial.println(MultiLevelSensor.id);

    // set initial values

    ThingPropertyValue initialOn = {.boolean = false};
    valveOn.setValue(initialOn);
    (void)valveOn.changedValueOrNull();
    digitalWrite(valvePin, LOW);
}

void loop() {

    recvWithEndMarker();
    showNewData();

    ThingPropertyValue MVal;
    MVal.number = moistLevel;
    moistureLevel.setValue(MVal);
    adapter->update();

    bool on = valveOn.getValue().boolean;
    if (on) {
        Serial.println("On");
        digitalWrite(valvePin, HIGH );
    } else {
        Serial.println("Off");
        digitalWrite(valvePin, LOW);
    }
    delay(1000);
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        String l = receivedChars;
        moistLevel = l.toInt();
        Serial.println(moistLevel);
        newData = false;
    }
}

Still the same results - serial monitor says it’s online, I can find the JSON schema at the address, but the Gateway won’t connect even with the supplied URL - I get a little yellow 400 when I save it. Tried rebooting the Gateway.

Question about the device:esp8266:moisture - are these key words that the Gateway uses in some manner or just a description?

Question about the device:esp8266:moisture - are these key words that the Gateway uses in some manner or just a description?

The id field is supposed to be a properly formatted URN, according to the spec.

Still the same results - serial monitor says it’s online, I can find the JSON schema at the address, but the Gateway won’t connect even with the supplied URL - I get a little yellow 400 when I save it. Tried rebooting the Gateway.

I’m guessing you’re trying to add the top-level URL. Since you’re representing two separate devices, you’ll need to add each one separately, so http://<ip-address>/things/device:esp8266:moisture and http://<ip-address>/things/device:esp8266:valve.