Aircoookie/Espalexa

So simple but so hard...

MVFarkas opened this issue · 9 comments

Hello guys,

I'm trying to "automate" one light of my bedroom, however i have some problems...

  • First, i'm trying to read the eletric current value of my circuit, but i tried everything and failed...
  • Second, how can i send back to alexa the status of the light with this value of eletric current?

Below, the layout of the circuit that i'm trying to do...

circuit_layout

I tried too the 3 WAY of nassir-malik, however the program was write to the ESP8266.

When i finish, i will post everything here...

Thanks in advance.

Here is the code that i'm basing the project

`#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include
#include "current_meter.h"

void prepareIds();
boolean connectWifi();
boolean connectUDP();
void startHttpServer();
void turnOnRelay();
void turnOffRelay();
void sendRelayState();
bool switchStatus;
//
/
/
// Code is tested with ESP8266 ESP-12E or NodeMcu
//
// You only need to modify folloing settings to get it to work woth Alexa and your network
const char
ssid = "enter your ssid name"; //enter your ssid/ wi-fi(case sensitive) router name - 2.4 Ghz only
const char
password = "enter your ssid password";
String device_name= "DemoSwitch";// you can chage the device name from "DemoSwitch" to anything
/
/
//Change the GPIO as needed
const int relayPin = 2; //D4=GPIO2 relay pin
int current_sensor_pin = 17;// A0=GPIO17 Analog input pin that sensor is attached to
int device_on_current_threshold;//if the current value (milliamps) is greater than this amount then the device is on
/
/
/
**/
unsigned int localPort = 1900; // local port to listen on
WiFiUDP UDP;
boolean udpConnected = false;
IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900; // local port to listen on

ESP8266WebServer HTTP(80);

boolean wifiConnected = false;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
String serial;
String persistent_uuid;
String switch1;
int deviceState;

boolean cannotConnectToWifi = false;

void setup() {
Serial.begin(115200);
EEPROM.begin(512);
pins_init();
// Setup Relay pin for output
pinMode(relayPin, OUTPUT);
prepareIds();

// Initialise wifi connection
wifiConnected = connectWifi();

// only proceed if wifi connection successful
if(wifiConnected){
udpConnected = connectUDP();
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
if (udpConnected){
// initialise pins if needed
startHttpServer();
attachInterrupt(digitalPinToInterrupt(0), calibrateOnCurrent, FALLING);
device_on_current_threshold = eepromRead();
Serial.println("Current value.....");
Serial.println("device_on_current_threshold");
}
}
}

void loop() {
HTTP.handleClient();
delay(1);

// if there's data available, read a packet
// check if the WiFi and UDP connections were successful
if(wifiConnected){
if(udpConnected){
// if there�s data available, read a packet
int packetSize = UDP.parsePacket();

  if(packetSize) {
    //Serial.println("");
    //Serial.print("Received packet of size ");
    //Serial.println(packetSize);
    //Serial.print("From ");
    IPAddress remote = UDP.remoteIP();
    
    for (int i =0; i < 4; i++) {
      //Serial.print(remote[i], DEC);
      if (i < 3) {
        //Serial.print(".");
      }
    }
    
   // Serial.print(", port ");
   // Serial.println(UDP.remotePort());
    
    int len = UDP.read(packetBuffer, 255);
    
    if (len > 0) {
        packetBuffer[len] = 0;
    }

    String request = packetBuffer;
    //Serial.println("Request:");
    //Serial.println(request);
     
    if(request.indexOf('M-SEARCH') > 0) {
        //if(request.indexOf("urn:Belkin:device:**") > 0) {
          if((request.indexOf("urn:Belkin:device:**") > 0) || (request.indexOf("ssdp:all") > 0) || (request.indexOf("upnp:rootdevice") > 0)) {
           // Serial.println("Responding to search request ...");
            respondToSearch();
        }
    }
  }
    
  delay(10);
}

} else {
// Turn on/off to indicate cannot connect ..
}

}

void prepareIds() {
uint32_t chipId = ESP.getChipId();
Serial.println("ChipId");
Serial.println(chipId);
char uuid[64];
sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
(uint16_t) ((chipId >> 16) & 0xff),
(uint16_t) ((chipId >> 8) & 0xff),
(uint16_t) chipId & 0xff);

serial = String(uuid);
persistent_uuid = "Socket-1_0-" + serial;
//device_name = "box";
}

void respondToSearch() {
//Serial.println("");
//Serial.print("Sending response to ");
//Serial.println(UDP.remoteIP());
//Serial.print("Port : ");
//Serial.println(UDP.remotePort());

IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);

String response = 
     "HTTP/1.1 200 OK\r\n"
     "CACHE-CONTROL: max-age=86400\r\n"
     "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
     "EXT:\r\n"
     "LOCATION: http://" + String(s) + ":80/setup.xml\r\n"
     "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
     "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
     "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
     "ST: urn:Belkin:device:**\r\n"
     "USN: uuid:" + persistent_uuid + "::urn:Belkin:device:**\r\n"
     "X-User-Agent: redsonic\r\n\r\n";

UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
UDP.write(response.c_str());
UDP.endPacket();                    

// Serial.println("Response sent !");

}

void startHttpServer() {
HTTP.on("/index.html", HTTP_GET, {
//Serial.println("Got Request index.html ...\n");
HTTP.send(200, "text/plain", "Hellow");
});

HTTP.on("/upnp/control/basicevent1", HTTP_POST, []() {
  Serial.println("########## Responding to  /upnp/control/basicevent1 ... ##########");      
  
  /*for (int x=0; x <= HTTP.args(); x++) {
    Serial.println(HTTP.arg(x));
  }*/
     
   //switchSource = "alexa";
  String request = HTTP.arg(0);      

  if(request.indexOf("<BinaryState>1</BinaryState>") > 0) {
      Serial.println("Got Turn on request");
      switchStatus=1;
      turnOnRelay();
  }

  if(request.indexOf("<BinaryState>0</BinaryState>") > 0) {
      Serial.println("Got Turn off request");

      turnOffRelay();
  }
  
  HTTP.send(200, "text/plain", "");
});


HTTP.on("/switch", HTTP_GET, []() {
  Serial.println("########## Responding to switch on/off get request ... ##########");      

  /*for (int x=0; x <= HTTP.args(); x++) {
    Serial.println(HTTP.arg(x));
  }*/

  int request = HTTP.arg(0).toInt();      
   
  if(request == 1) {
      Serial.println("Got switch Turn on request");
      digitalWrite(relayPin, HIGH);
      switch1 = "On";
  }

  if(request == 0) {
      Serial.println("Got switch Turn off request");
      digitalWrite(relayPin, LOW);
      switch1 = "Off";
  }

if(request.indexOf("GetBinaryState") >= 0) {
Serial.println("Got binary state request");
sendRelayState();
}

  HTTP.send(200, "text/plain", "Switch is " + switch1);
});



HTTP.on("/eventservice.xml", HTTP_GET, [](){
  Serial.println(" ########## Responding to eventservice.xml ... ########\n");
  String eventservice_xml = "<?scpd xmlns=\"urn:Belkin:service-1-0\"?>"
        "<actionList>"
          "<action>"
            "<name>SetBinaryState</name>"
            "<argumentList>"
              "<argument>"
                "<retval/>"
                "<name>BinaryState</name>"
                "<relatedStateVariable>BinaryState</relatedStateVariable>"
                "<direction>in</direction>"
              "</argument>"
            "</argumentList>"
             "<serviceStateTable>"
              "<stateVariable sendEvents=\"yes\">"
                "<name>BinaryState</name>"
                "<dataType>Boolean</dataType>"
                "<defaultValue>0</defaultValue>"
              "</stateVariable>"
              "<stateVariable sendEvents=\"yes\">"
                "<name>level</name>"
                "<dataType>string</dataType>"
                "<defaultValue>0</defaultValue>"
              "</stateVariable>"
            "</serviceStateTable>"
          "</action>"
        "</scpd>\r\n"
        "\r\n";
        
  HTTP.send(200, "text/plain", eventservice_xml.c_str());
});

HTTP.on("/setup.xml", HTTP_GET, [](){
  //Serial.println(" ########## Responding to setup.xml ... ########\n");

  IPAddress localIP = WiFi.localIP();
  char s[16];
  sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);

  String setup_xml = "<?xml version=\"1.0\"?>"
        "<root>"
         "<device>"
            "<deviceType>urn:Belkin:device:controllee:1</deviceType>"
            "<friendlyName>"+ device_name +"</friendlyName>"
            "<manufacturer>Belkin International Inc.</manufacturer>"
            "<modelName>Emulated Socket</modelName>"
            "<modelNumber>3.1415</modelNumber>"
            "<UDN>uuid:"+ persistent_uuid +"</UDN>"
            "<serialNumber>221517K0101769</serialNumber>"
            "<binaryState>0</binaryState>"
            "<serviceList>"
              "<service>"
                  "<serviceType>urn:Belkin:service:basicevent:1</serviceType>"
                  "<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>"
                  "<controlURL>/upnp/control/basicevent1</controlURL>"
                  "<eventSubURL>/upnp/event/basicevent1</eventSubURL>"
                  "<SCPDURL>/eventservice.xml</SCPDURL>"
              "</service>"
          "</serviceList>" 
          "</device>"
        "</root>\r\n"
        "\r\n";
        
    HTTP.send(200, "text/xml", setup_xml.c_str());
    
    //Serial.print("Sending :");
    //Serial.println(setup_xml);
});

HTTP.begin();  

// Serial.println("HTTP Server started ..");
}

// connect to wifi � returns true if successful or false if not
boolean connectWifi(){
boolean state = true;
int i = 0;

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("Connecting to WiFi");

// Wait for connection
Serial.print("Connecting ...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (i > 10){
state = false;
break;
}
i++;
}

if (state){
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
else {
Serial.println("");
Serial.println("Connection failed.");
}

return state;
}

boolean connectUDP(){
boolean state = false;

Serial.println("");
Serial.println("Connecting to UDP");

if(UDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti)) {
Serial.println("Connection successful");
state = true;
}
else{
Serial.println("Connection failed");
}

return state;
}

void turnOnRelay() {
Serial.println("turnOnRelay.....");
Serial.println(digitalRead(relayPin));
currentMeter();
Serial.print(digitalRead(relayPin));

if (deviceState == 0){
switchStatus=!digitalRead(relayPin);
digitalWrite(relayPin, !digitalRead(relayPin)); // turn off relay with voltage LOW

}

}

void turnOffRelay() {
Serial.println("turnOffRelay.....");
Serial.println(digitalRead(relayPin));
currentMeter();
Serial.print(digitalRead(relayPin));
if (deviceState == 1){
switchStatus=!digitalRead(relayPin);
digitalWrite(relayPin, !digitalRead(relayPin)); // turn off relay with voltage LOW

}
}
void sendRelayState() {
String body =
"<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"
"<u:GetBinaryStateResponse xmlns:u="urn:Belkin:service:basicevent:1">\r\n"
"";

body += (switchStatus ? "1" : "0");

body += "\r\n"
"</u:GetBinaryStateResponse>\r\n"
"</s:Body> </s:Envelope>\r\n";

HTTP.send(200, "text/xml", body.c_str());

Serial.print("Sending :");
Serial.println(body);
}`

And the current_meter.h below:

`#include <EEPROM.h>
extern int current_sensor_pin;
float amplitude_current; //amplitude current
float effective_value; //effective current
int sensor_max;
extern int deviceState;
extern int device_on_current_threshold;

void eepromWrite(int buffLocation, String ids);
int eepromRead(int buffLocation );

void pins_init()
{
pinMode(current_sensor_pin, INPUT);
}
/Function: Sample for 1000ms and get the maximum value from the SIG pin/
int getMaxValue()
{
int sensorValue; //value read from the sensor
int sensorMax = 0;
uint32_t start_time = millis();
while((millis()-start_time) < 1000)//sample for 1000ms
{
sensorValue = analogRead(current_sensor_pin);
if (sensorValue > sensorMax)
{
/record the maximum sensor value/
sensorMax = sensorValue;
}
}
return sensorMax;
}

void currentMeter()
{

sensor_max = getMaxValue();
//amplitude_current=(float)sensor_max/10245/2001000000;
//effective_value=amplitude_current/1.414;
//Serial.println("The effective value of the current is(in mA)");
//Serial.println(effective_value,1);
Serial.println("The effective value of the current is(in mA)");
Serial.println(sensor_max);
effective_value=sensor_max;
if(effective_value>device_on_current_threshold){
Serial.println("Switch was on");
deviceState = 1 ;
}else{
Serial.println("Switch was off");
deviceState = 0 ;
}
}

void eepromWrite(String ids)
{
for (int i = 0; i < 500; i++){
EEPROM.write(i, 0);
}
const char* id;
id= ids.c_str();
for (int i = 0; i < 500; i++){ //clear buffer before write
EEPROM.write(i, 0);
}
size_t i;

for(i=0; i<=strlen(id); i++) //write value to eeprom
{
EEPROM.write(i, (uint8_t) id[i]);
}
EEPROM.commit();
}

int eepromRead( ){
Serial.println("Reading EEPROM");
String doorStatus;
for (int i = 0; i < 500; ++i)
{
doorStatus += char(EEPROM.read(i));
}
//Serial.println(doorStatus.length());
Serial.print("Door Status: ");
Serial.println(doorStatus);
return doorStatus.toInt();
}
void calibrateOnCurrent(){
int vvl =getMaxValue();
Serial.println("Saving Calibrating current...");
Serial.println(vvl);
eepromWrite(String(vvl-5));
device_on_current_threshold = eepromRead();
Serial.println("Reading Calibrating current...");
Serial.println(device_on_current_threshold);
}
`

I spend about a month trying to solve and nothing :(

Hi!
Unfortunately I cannot help you with the current measurement or hardware parts of your project.
Also, reporting the current to Alexa is not directly possible with the Hue api Espalexa uses. You can however, set the brightness value of a Dimmable light to your current reading (the range is from 0-100%, so maybe 0.1amps = 1% might and 10amps = 100% might be a good mapping), which allows you to get the reading in the Alexa app.

@Aircoookie , I'm using now an VAC sensor instead of the Eletric Current sensor.

Another doubt... I only can send a feedback to Alexa app with setValue()?

I found these commands below in the Espalexa.h:

`if (body.indexOf("false")>0) //OFF command
{
devices[devId]->setValue(0);
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::off);
devices[devId]->doCallback();
return true;
}

  if (body.indexOf("true") >0) //ON command
  {
    devices[devId]->setValue(devices[devId]->getLastValue());
    devices[devId]->setPropertyChanged(EspalexaDeviceProperty::on);
  }`

The setProperty don't do that feedback? I'm asking all these questions because i want to do the automation simple and easy, ans the espalexa is the easiest way that i found.

Again.. thanks and all the best for you

Yes, only setValue() needs to be used to update the device value! The protocol doesn't allow sending this feedback to Alexa directly, but that is not a problem, since it will be sent once Alexa asks the API for the device the next time (which happens if you open the device in the Alexa app, for example)! setPropertyChanged() and doCallback() are internal functions, you do not need to use them :)

Ok! Thanks a lot <3

Hi!
Unfortunately I cannot help you with the current measurement or hardware parts of your project.
Also, reporting the current to Alexa is not directly possible with the Hue api Espalexa uses. You can however, set the brightness value of a Dimmable light to your current reading (the range is from 0-100%, so maybe 0.1amps = 1% might and 10amps = 100% might be a good mapping), which allows you to get the reading in the Alexa app.

Abou this... i don't want to send to Alexa the current (value).

I want to read the light status from a switch and tell to Alexa that the light is on, u know?

An exmaple:
...
int light = 15; //Pin attached to Relay
int lightstatus; //Variable to register the real status

if (analogRead(lightstatus)>200){

SET THE STATUS "ON" ON THE VIRTUAL BUTTON OF ALEXA

}
...

Does the Hue API supports that?

Ah, thanks for clarifying.
Use latest Espalexa 2.4.8, I've added a devices[devId]->setState(true) command!

I'm sorry to bother you, but do you have any examples of the application of setValue? Do I have to use it in a function outside the callback function?

I tried to set a timer to run the function to check the status of light sensor and setState of the device, however it doesn't work :(. I think that conflict with the callback function.

Callback function:

void alphaChanged(EspalexaDevice* d) {
  if (d == nullptr) return; //this is good practice, but not required
  Serial.print("A changed to ");
  if (d->getValue()){
    Serial.println("ON");
    digitalWrite(light, HIGH);
  }
  else {
    Serial.println("OFF");
    digitalWrite(light, LOW);
  }
}

Light Status function:

void verifyStatusLamp(){ 
  for (int i = 0; i < 250; i++){ 
    Actualstatus = analogRead(lightstatus);
  }   
  if(Actualstatus > 200 && alpha->getState() == false){ 
      alpha->setState(true);
  }else if(Actualstatus < 200 && alpha->getState() == true){ 
      alpha->setState(false);
    }
}

have u had discovered something?