Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Using a pushbutton to toggle a dashboard switch
Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Please be positive and constructive with your questions and comments.

Using a pushbutton to toggle a dashboard switch

by jefish on Sun Dec 01, 2019 4:06 am

I'm building a IO-controlled xmas tree light switch, and have run into a problem. My criteria are:

1) Toggle switch on dashboard (powerswitch feed) to tell ESP to turn a relay on or off <done>
2) Light on the dashboard (powerlight feed); value set from the ESP after the relay is switched, to show message success <done>
3) Physical momentary button to manually toggle the IO powerswitch <record scratch>

The issue I'm trying to solve with #3 is this; I turn off the lights with the IO toggle. Wife gets up in the morning and wants to turn them back on, which would be a lot easier with a physical button. So far I've gotten halfway there. :)

I'm using powerlight as a value, and want to set the powerswitch to the opposite of powerlight (toggle it on or off based on the current state). I've tried using powerswitch as a the source state, but was getting some double-replies from IO. Also tried reading the RELAY_PIN value and using that as the source. Any value would be fine, whatever I can use to say "set powerswitch to not-that."

So, if the dashboard powerlight is On, pressing the button WILL turn off powerswitch.
Serial shows:
23:26:24.600 -> Button pressed
23:26:24.847 -> IO switch is OFF

If the dashboard powerlight is Off, pressing the button will NOT turn on powerswitch.
Serial shows:
23:26:00.903 -> Button pressed
23:26:01.081 -> IO switch is OFF

Code: Select all | TOGGLE FULL SIZE
#include "config.h"
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#define LED_PIN 2
#define RELAY_PIN 4
#define BUTTON_PIN 14

const char* ssid = "SSID";
const char* password = "PASS";
AdafruitIO_Feed *powerswitch = io.feed("powerswitch");
AdafruitIO_Feed *powerlight = io.feed("powerlight");

int button;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(LED_PIN, HIGH);
  digitalWrite(RELAY_PIN, LOW);

  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    delay(3000);
    ESP.restart();
  } 
 
  ArduinoOTA.setHostname("TreeESP");
  ArduinoOTA.begin();

  Serial.print("Connecting to Adafruit IO");
  io.connect();

  powerswitch->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println();
  Serial.println(io.statusText());
  powerswitch->get();
}

void loop() {
  io.run();
  ArduinoOTA.handle();

  button = digitalRead(BUTTON_PIN);

  if (button == LOW) {
    Serial.println("Button pressed");
    powerlight->get();
    powerswitch->save(!powerlight);
  }

}

void handleMessage(AdafruitIO_Data *data) {
 
  if(data->toPinLevel() == HIGH) {
    Serial.println("IO switch is ON");
    digitalWrite(RELAY_PIN, HIGH);
  }
  else {
    Serial.println("IO switch is OFF");
    digitalWrite(RELAY_PIN, LOW);
  }
  digitalWrite(LED_PIN, !data->toPinLevel());
  powerlight->save(data->toPinLevel());
}

jefish
 
Posts: 45
Joined: Fri Sep 12, 2014 2:08 am

Re: Using a pushbutton to toggle a dashboard switch

by jefish on Mon Dec 02, 2019 5:00 pm

Short version: I'd like to single-press a physical button to toggle a aio switch on/off or 1/0.

jefish
 
Posts: 45
Joined: Fri Sep 12, 2014 2:08 am

Re: Using a pushbutton to toggle a dashboard switch

by llaverne on Fri Dec 06, 2019 12:13 pm

If you know how to use 2-way communication, then simply use a register/variable in the Arduino sketch to keep track of switch state. Then, at each connection to IO, register to the switch topic, check it's on-line state, and do a comparison to the Arduinos recorded switch state. If the Arduino says it's OFF, but IO says ON, then you know that the online switch was activated, so flip the relay to ON. If on he other hand, when the Arduino connects to IO, the switch is OFF in IO, but the Arduino says ON (that is, someone pressed the physical switch), then simply send ON to IO. Repeat.

llaverne
 
Posts: 1
Joined: Fri Oct 04, 2019 1:36 am

Re: Using a pushbutton to toggle a dashboard switch

by jefish on Sat Dec 07, 2019 3:28 am

Yep, that's what I've been trying. The trouble is, the state of powerlight always comes back as 1, even when the dashboard shows it at 0. I did find that I wasn't fetching the powerlight state when pressing the button, that has been remedied in the new code below. But still having troubles.

- In setup, it does an initial powerswitch->get() and sets the relay and onboard LED to echo that state. This works fine.
- In handleMessage, it monitors messages from io powerswitch and sets the relay, onboard LED, and io powerlight value to echo any changes to that state. This also works.
- But in loop, it runs powerlight->get() on buttonpress and sets that to int lightstate. This is where things fall apart.

If the dashboard switch and light are on and I toggle the switch, I get
IO powerswitch is now OFF
Setting IO powerlight to 0

If the dashboard switch and light are off and I toggle the switch, I get
IO powerswitch is now ON
Setting IO powerlight to 1

This is all fine.

If the dashboard switch and light are on and I press the physical button, I get
Button pressed
IO powerlight is currently 1 // this looks right, but stand by
Setting IO powerswitch to 0 // this shows that my "set switch to not-light" is working
IO powerswitch is now OFF // this is handleMessage reacting to the loop and...
Setting IO powerlight to 0 // setting the light to match the new switch state

This is also fine; the local LED and relay shut off, and the dashboard state is accurate.

But the problem is revealed when the dashboard switch and light are off and I press the physical button
Button pressed
IO powerlight is currently 1 // **THIS IS WRONG**
Setting IO powerswitch to 0 // it already was
IO powerswitch is now OFF // as I said
Setting IO powerlight to 0 // and so was this

I've tried using if lightstate == 1 { else, and if lightstate == HIGH { else, and ... jeez, a few other things. Unless powerlight->get() comes back with a real value, I'm sunk.

Latest code here
Code: Select all | TOGGLE FULL SIZE
#include "config.h"
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#define LED_PIN 2
#define RELAY_PIN 4
#define BUTTON_PIN 14

const char* ssid = "SSID";
const char* password = "PASS";
AdafruitIO_Feed *powerswitch = io.feed("powerswitch");
AdafruitIO_Feed *powerlight = io.feed("powerlight");

int button;
int lightstate;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(LED_PIN, HIGH);
  digitalWrite(RELAY_PIN, LOW);

  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    delay(3000);
    ESP.restart();
  } 
 
  ArduinoOTA.setHostname("TreeESP");
  ArduinoOTA.begin();

  Serial.print("Connecting to Adafruit IO");
  io.connect();

  powerswitch->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println();
  Serial.println(io.statusText());
  powerswitch->get();
}

void loop() {
  io.run();
  ArduinoOTA.handle();

  button = digitalRead(BUTTON_PIN);

  if (button == LOW) {
    Serial.println("Button pressed");
    lightstate = powerlight->get();
    Serial.print("IO powerlight is currently ");
    Serial.println(lightstate);
    Serial.print("Setting IO powerswitch to ");
    Serial.println(!lightstate);
    powerswitch->save(!lightstate);
  }
}

void handleMessage(AdafruitIO_Data *data) {
 
  if(data->toPinLevel() == HIGH) {
    Serial.println("IO powerswitch is now ON");
    digitalWrite(RELAY_PIN, HIGH);
  }
  else {
    Serial.println("IO powerswitch is now OFF");
    digitalWrite(RELAY_PIN, LOW);
  }
  digitalWrite(LED_PIN, !data->toPinLevel());
  Serial.print("Setting IO powerlight to ");
  Serial.println(data->toPinLevel());
  powerlight->save(data->toPinLevel());
}

jefish
 
Posts: 45
Joined: Fri Sep 12, 2014 2:08 am

Re: Using a pushbutton to toggle a dashboard switch

by jefish on Mon Dec 23, 2019 3:05 am

Any tips on successfully fetching the value of a feed from IO?

jefish
 
Posts: 45
Joined: Fri Sep 12, 2014 2:08 am

Re: Using a pushbutton to toggle a dashboard switch

by brubell on Mon Dec 23, 2019 11:59 am

jefish wrote:Any tips on successfully fetching the value of a feed from IO?


Yep! You'll want to implement the /get feature of Adafruit IO Arduino..

The way it works is that for any given Adafruit IO MQTT feed topic (groups coming soon), subscribe to the feed topic, then add /get to the topic and publish anything to that new topic (our Arduino library uses the null character: '\0') . IO will immediately publish, just for that client, the most recent value received on the feed.

For example, if I have a Feather HUZZAH subscribed to a counter feed: abachman/f/counter, and I want to get the latest value when I connect, I could publish to abachman/f/counter/get and immediately receive a message on abachman/f/counter with the last value that feed received.


Code: Select all | TOGGLE FULL SIZE
// ... from the adafruitio_01_subscribe example sketch
AdafruitIO_Feed *counter = io.feed("counter");

void setup() {

  // 1. start IO connection
  io.connect();

  // 2. prepare MQTT subscription with handler function
  counter->onMessage(handleMessage);

  // 3. wait for successful connection
  while(io.mqttStatus() < AIO_CONNECTED) {
    delay(500);
  }

  // 4. send /get message, requesting last value
  counter->get(); // ask Adafruit IO to resend the last value

}
// ....


via https://io.adafruit.com/blog/notebook/2 ... -features/

brubell
 
Posts: 1043
Joined: Fri Jul 17, 2015 10:33 pm

Please be positive and constructive with your questions and comments.