esp8266-esp32-sdk icon indicating copy to clipboard operation
esp8266-esp32-sdk copied to clipboard

Modes in Sinric Pro with Humidifier

Open Tharos88 opened this issue 1 year ago • 10 comments

Hi.

I'm working with the Sinric Pro modes on a humidifier that works in sequential mode, that is, it enters the first mode (30 minutes), then the second mode (60 minutes), then the third mode (120 minutes) and then the fourth mode (180 minutes) and then it turns off. This is done with a push button. To change from one mode to another sequentially, I'm simulating the pulse of the physical push button with a low signal from an ESP8266 pin, however, I haven't been able to get it to go from the third mode to the second mode, for example, taking into account that it must be sequential. I've tried with conditionals, switch cases, flags, but I haven't been able to. I don't know if I can use the sendModeEvent function, so that, if there is an update to the mode, the pin gives the necessary pulses to reach the mode I want the humidifier to work in.

I hope I make myself understood and thank you very much for the support. Please, let me know if I must to upload the code.

Tharos88 avatar Aug 27 '24 03:08 Tharos88

Code without the credentials would be helpful to understand further

On Tue, 27 Aug 2024 at 10:04 AM Alefox @.***> wrote:

Hi.

I'm working with the Sinric Pro modes on a humidifier that works in sequential mode, that is, it enters the first mode (30 minutes), then the second mode (60 minutes), then the third mode (120 minutes) and then the fourth mode (180 minutes) and then it turns off. This is done with a push button. To change from one mode to another sequentially, I'm simulating the pulse of the physical push button with a low signal from an ESP8266 pin, however, I haven't been able to get it to go from the third mode to the second mode, for example, taking into account that it must be sequential. I've tried with conditionals, switch cases, flags, but I haven't been able to. I don't know if I can use the sendModeEvent function, so that, if there is an update to the mode, the pin gives the necessary pulses to reach the mode I want the humidifier to work in.

I hope I make myself understood and thank you very much for the support. Please, let me know if I must to upload the code.

— Reply to this email directly, view it on GitHub https://github.com/sinricpro/esp8266-esp32-sdk/issues/401, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZAZZSYR744BJM4RZKMIQLZTPUFJAVCNFSM6AAAAABNFF7A66VHI2DSMVQWIX3LMV43ASLTON2WKOZSGQ4DQMJVGYZTONI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

kakopappa avatar Aug 27 '24 03:08 kakopappa

Hi, @kakopappa

This is the code I use to simulate the pulse the physical push button:

void modoHumidificador(void){

globalPowerState_1 = true; if(globalPowerState_1){ if(globalModes1["modeInstance1"] == "Modo_Uno"){ a = 1; b = 1; i = 1; modeFlag_1 = true; } if(globalModes1["modeInstance1"] == "Modo_Dos"){ a = 2; b = 2; i = 2; modeFlag_2 = true; } if(globalModes1["modeInstance1"] == "Modo_Tres"){ a = 3; b = 3; i = 3; modeFlag_3 = true; } if(globalModes1["modeInstance1"] == "Modo_Cuatro"){ a = 4; b = 4; i = 4; modeFlag_4 = true; } } } //---------------------------------------------------------------------------------------------------// void modos(void){ switch(a){ case 0: digitalWrite(modeButton, HIGH); break; case 1: //Modo_Uno digitalWrite(modeButton, LOW); delay(300); digitalWrite(modeButton, HIGH); delay(300); break; case 2: //Modo_Dos for(int b = 1; b <= 2; b++){ digitalWrite(modeButton, LOW); delay(300); digitalWrite(modeButton, HIGH); delay(300); } break; case 3: //Modo_Tres for(int b = 1; b <= 3; b++){ digitalWrite(modeButton, LOW); delay(300); digitalWrite(modeButton, HIGH); delay(300); } break; case 4: //Modo_Cuatro for(int b = 1; b <= 4; b++){ digitalWrite(modeButton, LOW); delay(300); digitalWrite(modeButton, HIGH); delay(300); } break; default: break; } } //----------------------------------------------------------------------------------------//

As you seen, to select, e.j., the fourth mode, the ESP8266 must to send four pulses in Low. The idea is, if the humidifier is in mode four and I'd like to change to the mode three, the microcontroller sent the necessary pulses to go to the mode three.

Thank you so much.

Tharos88 avatar Aug 27 '24 03:08 Tharos88

If I get you right, this question is not about SinricPro but how many pulses you need to send.

What you need is something like a lookup table for how many pulses you have to do in relation to the current mode:

c/d 0 1 2 3 4
0 - 1 2 3 4
1 4 - 1 2 3
2 3 4 - 1 2
3 2 3 4 - 1
4 1 2 3 4 -

Example

If you want to go from (c)urrent mode 3 to (d)estination mode 2 you have to do 4 pulses

c/d 0 1 >2< 3 4
0 - 1 2 3 4
1 4 - 1 2 3
2 3 4 - 1 2
>3< 2 3 >4< - 1
4 1 2 3 4 -

sivar2311 avatar Aug 27 '24 03:08 sivar2311

The pulse count can also simply calculated:

int calculatePulseCount(int currentMode, int destMode, int maxMode = 4) {
  if (currentMode == destMode) return 0;
  return currentMode < destMode ? destMode - currentMode : (maxMode+1) - (currentMode - destMode);
}

A small test function

void listAllPulseCount() {
  for (int source = 0; source < 5; source ++) {
    for (int dest = 0; dest < 5; dest ++) {
      int pulseCount = calculatePulseCount(source, dest);
      Serial.printf("current mode: %d, destination mode: %d, pulse count: %d\r\n", source, dest, pulseCount);
    }
  }
}

outputs:

current mode: 0, destination mode: 0, pulse count: 0
current mode: 0, destination mode: 1, pulse count: 1
current mode: 0, destination mode: 2, pulse count: 2
current mode: 0, destination mode: 3, pulse count: 3
current mode: 0, destination mode: 4, pulse count: 4
current mode: 1, destination mode: 0, pulse count: 4
current mode: 1, destination mode: 1, pulse count: 0
current mode: 1, destination mode: 2, pulse count: 1
current mode: 1, destination mode: 3, pulse count: 2
current mode: 1, destination mode: 4, pulse count: 3
current mode: 2, destination mode: 0, pulse count: 3
current mode: 2, destination mode: 1, pulse count: 4
current mode: 2, destination mode: 2, pulse count: 0
current mode: 2, destination mode: 3, pulse count: 1
current mode: 2, destination mode: 4, pulse count: 2
current mode: 3, destination mode: 0, pulse count: 2
current mode: 3, destination mode: 1, pulse count: 3
current mode: 3, destination mode: 2, pulse count: 4
current mode: 3, destination mode: 3, pulse count: 0
current mode: 3, destination mode: 4, pulse count: 1
current mode: 4, destination mode: 0, pulse count: 1
current mode: 4, destination mode: 1, pulse count: 2
current mode: 4, destination mode: 2, pulse count: 3
current mode: 4, destination mode: 3, pulse count: 4
current mode: 4, destination mode: 4, pulse count: 0

sivar2311 avatar Aug 27 '24 15:08 sivar2311

Hi @sivar2311 Thank you for your help. I'm trying to understand the code that you send. Meanwhile, ¿Where I can put the code to, e.j., when I tell to Alexa that sets Mode 1 if the current mode is 3?

Tharos88 avatar Aug 28 '24 01:08 Tharos88

Hi @Tharos88 !

I'm trying to understand the code that you send.

The calculatePulseCount function only calculates the number of pulses you need to send to switch from one mode to another.

The code actually works quite simply:

if (currentMode == destMode) return 0;

If the current mode is the same as the destination mode, 0 is returned and the function stops here. Otherwise the next line is executed:

return currentMode < destMode ? destMode - currentMode : (maxMode+1) - (currentMode - destMode);

which is the short term of

if (currentMode < destMode) {
  return destMode - currentMode;
} else {
  return (maxMode + 1) - (currentMode - destMode);
}

Where I can put the code to,

To be able to use this code, you have to do a little more, such as converting the mode numbers to mode names (int to string) and vice versa to compare them with the requested mode. The code should be used inside your onSetMode-Callback function ?!

when I tell to Alexa that sets Mode 1 if the current mode is 3?

This is confusing me. Why would you do this? This would mean that my original assumption from above (“If I get you right, this question is not about SinricPro but how many pulses you need to send.”) is completely wrong. Unfortunately you did not reply to this. Please explain this usecase in detail.

sivar2311 avatar Aug 28 '24 04:08 sivar2311

Hi, @sivar2311 I'm so sorry if I didn't express myself well. Although it's not exactly a Sinric Pro-bug, you've helped me with the problem I'm having. Now I'm clearer about what I should use the function in the onSetMode-Callback. I'd like to use the function you sent me so that when switching functions, it selects the pulses that are in the switch-case. I mean, that I can use the 'pulse count' variable to select the necessary pulses that are in the switch-case. How could I do that? Thank you very much in advance for all your help and patience.

Tharos88 avatar Aug 29 '24 02:08 Tharos88

Hi @Tharos88 !

You have to keep the current mode in a global variable. You need a function that converts a mode name into an integer value. In the callback function, you can then convert the current mode and the (target) mode into a number. You can use these numbers to calculate the number of pulses with the function from above.

Here is an example snippet (not tested!):

const String MODE_NAMES[]{
    "OFF",    // Name for Mode 0 
    "MODE 1", // Name for Mode 1 
    "MODE 2", // Name for Mode 2 
    "MODE 3", // Name for Mode 3 
    "MODE 4"  // Name for Mode 4 
};

const size_t MAX_MODE = sizeof(MODE_NAMES) / sizeof(MODE_NAMES[0]);

String currentMode = MODE_NAMES[0];

int calculatePulseCount(int currentMode, int destMode) {
  if (currentMode == destMode) return 0;
  return currentMode < destMode ? destMode - currentMode : MAX_MODE - (currentMode - destMode);
}

int getModeNumber(const String& modeName) {
    size_t i = 0;
    for (const String& name : MODE_NAMES) {
        if (MODE_NAMES[i] == modeName) return i;
        i++;
    }
    return 0;
}

bool onSetMode(const String& deviceId, const String& instance, String& mode) {
    int currentModeNumber = getModeNumber(currentMode);
    int newModeNumber = getModeNumber(mode);

    sendPulse(calculatePulseCount(currentModeNumber, newModeNumber));

    currentMode = mode;

    return true;
}

sivar2311 avatar Aug 29 '24 03:08 sivar2311

Using a Range Controller with named presets simplifies this scenario a lot:

image

Template Code
{
  "name": "Humidifier",
  "description": "Humidifier",
  "deviceTypeId": "5ff0b112994fd31b7d5e8065",
  "capabilities": [
    {
      "id": "5ff0b30e994fd31b7d5e865b"
    },
    {
      "id": "5ff0b45f994fd31b7d5e89c2",
      "range": {
        "instanceId": "mode",
        "locale": "en-US",
        "rangeName": "mode",
        "minimumValue": 0,
        "maximumValue": 4,
        "precision": 1,
        "unitOfMeasure": "600e7986a7a09c3f3230f8fb",
        "presets": [
          {
            "name": "Mode 1",
            "value": 1
          },
          {
            "name": "Mode 2",
            "value": 2
          },
          {
            "name": "Mode 3",
            "value": 3
          },
          {
            "name": "Mode 4",
            "value": 4
          }
        ],
        "nonControllable": false
      }
    }
  ]
}
Sketch (ESP32)
Humidifier.h
#ifndef _HUMIDIFIER_H_
#define _HUMIDIFIER_H_

#include <SinricProDevice.h>
#include <Capabilities/RangeController.h>
#include <Capabilities/PowerStateController.h>

class Humidifier 
: public SinricProDevice
, public RangeController<Humidifier>
, public PowerStateController<Humidifier> {
  friend class RangeController<Humidifier>;
  friend class PowerStateController<Humidifier>;
public:
  Humidifier(const String &deviceId) : SinricProDevice(deviceId, "Humidifier") {};
};

#endif
main.cpp
#include <Arduino.h>
#include <WiFi.h>
#include <SinricPro.h>
#include "Humidifier.h"

const char* APP_KEY    = "xxxx";
const char* APP_SECRET = "xxxx";
const char* DEVICE_ID  = "xxxx";

const char* WIFI_SSID = "xxxx";
const char* WIFI_PASS = "xxxx";

const size_t MAX_MODE = 5;

Humidifier &humidifier = SinricPro[DEVICE_ID];

bool globalPowerState;
int  globalMode;

void sendPulse(int pulseCount) {
    if (pulseCount == 0) return;

    // implement the send pulse function here
};

int calculatePulseCount(int currentMode, int destMode) {
    if (currentMode == destMode) return 0;
    return currentMode < destMode ? destMode - currentMode : MAX_MODE - (currentMode - destMode);
}

void changeMode(int currentMode, int newMode) {
    if (currentMode == newMode) return;

    int pulseCount = calculatePulseCount(currentMode, newMode);
    sendPulse(pulseCount);
}

bool onRangeValue(const String &deviceId, const String &instance, int &rangeValue) {
    int currentMode = globalMode;
    int newMode = rangeValue;

    changeMode(currentMode, newMode);

    globalMode = newMode;
    return true;
}

bool onAdjustRangeValue(const String &deviceId, const String &instance, int &valueDelta) {
    int currentMode = globalMode;
    int newMode = globalMode += valueDelta;

    globalMode = newMode;

    changeMode(currentMode, newMode);

    valueDelta = newMode;
    return true;
}

void setupSinricPro() {
    humidifier.onRangeValue("mode", onRangeValue);
    humidifier.onAdjustRangeValue("mode", onAdjustRangeValue);

    SinricPro.onConnected([] { Serial.printf("[SinricPro]: Connected\r\n"); });
    SinricPro.onDisconnected([] { Serial.printf("[SinricPro]: Disconnected\r\n"); });
    SinricPro.begin(APP_KEY, APP_SECRET);
};

void setupWiFi() {
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    Serial.printf("[WiFi]: Connecting to %s", WIFI_SSID);
    while (WiFi.status() != WL_CONNECTED) {
        Serial.printf(".");
        delay(250);
    }
    Serial.printf("connected\r\n");
}

void setup() {
    Serial.begin(115200);
    setupWiFi();
    setupSinricPro();
}

void loop() {
    SinricPro.handle();
}

sivar2311 avatar Aug 30 '24 05:08 sivar2311

The more I think about this, presets don't even need to be set...

sivar2311 avatar Aug 30 '24 07:08 sivar2311

Ping @Tharos88

sivar2311 avatar Aug 31 '24 06:08 sivar2311