openHASP: An MQTT driven Touchscreen / Scene controller

Maybe someone will let you know when they are in the mood.

2 Likes

Where did you buy it?

aliexpress 9.32US: https://aliexpress.ru/item/1005005865107357.html?spm=a2g2w.orderdetail.0.0.545b4aa6KzDu99&sku_id=12000034624084330

Article: Пультик-Шпультик для умного дома — Сообщество «Сделай Сам» на DRIVE2
use translator if needed.

Grabcad 3D model: https://grabcad.com/library/esp32-2432s024c-1

thingiverse case: https://www.thingiverse.com/thing:6274345

Can anyone see any issues with my configuration of a button? All my other light.entities work fine but as soon as i try switch.entities it doesnt work.

- obj: "p3b1" # bedroom heater btn with toggle true
      properties:
        "val": '{{ 1 if is_state("switch.bed_heater_shelly_7", "on") else 0 }}'
        "text": "\uE438 Bed Heater"
      event:
        "down":
          - service: homeassistant.toggle
            entity_id: "switch.bed_heater_shelly_7"
{"page":3,"id":1,"obj":"btn","x":5,"y":40,"w":310,"h":50,"toggle":true,"text":"\uE438 Bed Heater","text_font":32,"align":1}

Think it might be something to do either the toggle true. Would changing the event from down to up possibly fix my issue??

Any advice much appreciated.

Toggle objects send on and off events instead of the up, down, etc…
So you need to change the event to on and off in your yaml.

In case if someone needs. to use GPIO as input pin to measure battery voltage you have to use custom files:

my_custom.h file:

/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
   For full license information read the LICENSE file in the project folder */

// USAGE: - Copy this file and rename it to my_custom.h
//        - uncomment in your user_config_override.h the line containing #define HASP_USE_CUSTOM 1
//

#ifndef HASP_CUSTOM_H
#define HASP_CUSTOM_H

#include "hasplib.h"
#if defined(HASP_USE_CUSTOM)

/* This function is called at boot */
void custom_setup();

/* This function is called every itteration of the main loop */
void custom_loop();

/* This function is called every second */
void custom_every_second();

/* This function is called every 5 seconds */
void custom_every_5seconds();

/* This function is called when battery voltage is below 15% */
void low_bat_alert(int pin, int duration);

/* return true if the pin used by the custom code */
bool custom_pin_in_use(uint8_t pin);

/* Add a key which defines a JsonObject to add to the sensor JSON output */
void custom_get_sensors(JsonDocument& doc);

/* Receive custom topic & payload messages */
void custom_topic_payload(const char* topic, const char* payload, uint8_t source);

#endif // HASP_USE_CUSTOM

#endif // HASP_CUSTOM_H

my_custom.cpp file:

/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
   For full license information read the LICENSE file in the project folder */

// USAGE: - Copy this file and rename it to my_custom.cpp
//        - Change false to true on line 9

#include "hasplib.h"

#if defined(HASP_USE_CUSTOM) && true // <-- set this to true in your code

#include "hasp_debug.h"
#include "custom/my_custom.h"

unsigned long last_blink = 0;
bool blink_state = LOW;

const int LED_BUILTIN1 = 4;  //red
const int LED_BUILTIN2 = 16; //green
const int LED_BUILTIN3 = 17; //blue
const int voltage_read = 35;
const int illum_read = 34;
const int blink_speed = 10000; //read every 10sec

float batteryFraction;
float voltageLevel;
int vbat;
int illum;

// Implement heartbeat led
const int fadeTime = 1000; 
unsigned long lastMillis = 0;
int brightness = 0;
int fadeDirection = 1;  // 1 for fading in, -1 for fading out

//Voltage read
const int MAX_ANALOG_VAL = 4095;
const float MAX_BATTERY_VOLTAGE = 4.2; // Max LiPoly voltage of a 3.7 battery is 4.2

void custom_setup()
{
    // Initialization code here
    last_blink = millis();
    //pinMode(LED_BUILTIN1, OUTPUT);
    //digitalWrite(LED_BUILTIN1, LOW);
    //pinMode(LED_BUILTIN2, OUTPUT);
    //digitalWrite(LED_BUILTIN2, LOW);
    //pinMode(LED_BUILTIN3, OUTPUT);
    //digitalWrite(LED_BUILTIN3, LOW);   
    pinMode(voltage_read, INPUT);
    pinMode(illum_read, INPUT);
    randomSeed(millis());
}

void custom_loop()
{
    // read voltage every 10 seconds
    if(blink_speed && (millis() - last_blink > blink_speed)) {

        vbat = analogRead(voltage_read);
        illum = analogRead(illum_read);
        voltageLevel = (vbat / 4095.0) * 4.2; // calculate voltage level
        batteryFraction = voltageLevel / MAX_BATTERY_VOLTAGE*100;

        if (batteryFraction <= 15) {
            low_bat_alert(LED_BUILTIN1, fadeTime);
        } 
        last_blink = millis();
    }
}

// Function to update the LED brightness for a heartbeat effect
void low_bat_alert(int pin, int duration) {
  unsigned long currentMillis = millis();

  // Check if it's time to update the LED brightness
  if (currentMillis - lastMillis >= duration / 255) {
    lastMillis = currentMillis;

    // Update brightness based on the fade direction
    brightness += fadeDirection;

    // Change direction if reaching maximum or minimum brightness
    if (brightness >= 255 || brightness <= 0) {
      fadeDirection *= -1;
    }

    analogWrite(pin, brightness);
  }
}

void custom_every_second()
{
    Serial.print("#");
}

void custom_every_5seconds()
{
    LOG_VERBOSE(TAG_CUSTOM, "%d seconds have passsed...", 5);


    // Convert the integer to a string
    String vbatFraction = String(batteryFraction);
    String vbatLevel = String(voltageLevel);
    String illumLevel = String(illum);

    // Create the JSON string
    String jsonString = "{\"vbat_Fraction\":" + vbatFraction + "}";
    String jsonString2 = "{\"vbat_Level\":" + vbatLevel + "}";
    String jsonString3 = "{\"illum_Level\":" + illumLevel + "}";

    // Convert the JSON string to a const char* for your function
    const char* jsonChar = jsonString.c_str();
    const char* jsonChar2 = jsonString2.c_str();
    const char* jsonChar3 = jsonString3.c_str();


    // Call your function with the JSON string

    dispatch_state_subtopic("vbat_Fraction", jsonChar);
    dispatch_state_subtopic("vbat_Level", jsonChar2);  
    dispatch_state_subtopic("illum_Level", jsonChar3); 
    
}


bool custom_pin_in_use(uint8_t pin)
{
    
    switch(pin) {
        case illum_read:  // Custom LED pin
        case 6:  // Custom Input pin
            return true;
        default:
            return false;
    }
    
}

void custom_get_sensors(JsonDocument& doc)
{
    JsonObject sensor = doc.createNestedObject(F("Temperature"));  // Add Key
    sensor[F("Temperature")] = random(256);                        // Set Value
}

void custom_topic_payload(const char* topic, const char* payload, uint8_t source){
    // Not used
}

#endif // HASP_USE_CUSTOM

my pages file:

{"page":0,"id":1,"obj":"label","x":3,"y":5,"h":30,"w":62,"text":"00:00","align":0,"bg_color":"#2C3E50","text_color":"#FFFFFF"}
{"page":0,"id":2,"obj":"btn","action":"prev","x":0,"y":290,"w":79,"h":32,"bg_color":"#2C3E50","text":"\uE141","text_color":"#FFFFFF","radius":0,"border_side":0,"text_font":28}
{"page":0,"id":3,"obj":"btn","action":"back","x":80,"y":290,"w":80,"h":32,"bg_color":"#2C3E50","text":"\uE2DC","text_color":"#FFFFFF","radius":0,"border_side":0,"text_font":22}
{"page":0,"id":4,"obj":"btn","action":"next","x":161,"y":290,"w":79,"h":32,"bg_color":"#2C3E50","text":"\uE142","text_color":"#FFFFFF","radius":0,"border_side":0,"text_font":28}
{"page":0,"id":5,"obj":"btn","x":215,"y":-3,"w":30,"h":40,"text_font":"2","text":"\uE5A9","text_color":"gray","bg_opa":0,"border_width":0}
{"page":0,"id":6,"obj":"bar","groupid":4,"x":170,"y":7,"w":40,"h":20,"align":0,"text_font":16,"text_color":"#FFFFFF","min":1,"max":100}

{"page":1,"id":0,"prev":10}
{"page":10,"id":0,"next":1}

{"page":1,"Salon":"---------- Page 1 ----------"}
{"page":1,"id":8,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Studia","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":1,"id":9,"obj":"label","x":47,"y":5,"h":30,"w":45,"text":"00.0","align":2,"bg_color":"#2C3E50","text_color":"#FFFFFF"}
{"page":1,"id":25,"obj":"btn","x":10,"y":40,"w":220,"h":90,"toggle":true,"text":"SALON","text_font":32,"mode":"break","align":1}

{"page":1,"id":26,"obj":"btn","x":10,"y":140,"w":220,"h":90,"toggle":true,"text":"KITCHEN","text_font":32,"mode":"break","align":1}


{"page":3,"Entrance":"---------- Page 2 ----------"}
{"page":3,"id":11,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Entrance","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":3,"id":19,"obj":"btn","x":10,"y":40,"w":220,"h":90,"toggle":true,"text":"\uE335","text_font":32,"mode":"break","align":1}
{"page":3,"id":20,"obj":"cpicker","x":15,"y":140,"w":140,"h":140}
{"page":3,"id":21,"obj":"slider","x":200,"y":140,"w":14,"h":140,"min":1,"max":255}

{"page":4,"Kids Room":"---------- Page 3 ----------"}
{"page":4,"id":12,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Kids Room","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":4,"id":21,"obj":"btn","x":10,"y":40,"w":220,"h":90,"toggle":true,"text":"\uE335","text_font":32,"mode":"break","align":1}
{"page":4,"id":22,"obj":"cpicker","x":15,"y":140,"w":140,"h":140}
{"page":4,"id":23,"obj":"slider","x":200,"y":140,"w":14,"h":140,"min":1,"max":255}

{"page":5,"Sport Room":"---------- Page 4 ----------"}
{"page":5,"id":13,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Sport Room","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":5,"id":14,"obj":"btn","x":10,"y":40,"w":220,"h":90,"toggle":true,"text":"\uE335","text_font":32,"mode":"break","align":1}
{"page":5,"id":15,"obj":"cpicker","x":15,"y":140,"w":140,"h":140}
{"page":5,"id":16,"obj":"slider","x":200,"y":140,"w":14,"h":140,"min":1,"max":255}


{"page":6,"Bedroom":"---------- Page 5 ----------"}
{"page":6,"id":16,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Bedroom","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":6,"id":17,"obj":"label","x":165,"y":5,"h":30,"w":45,"text":"00.0","align":2,"bg_color":"#2C3E50","text_color":"#FFFFFF"}
{"page":6,"id":23,"obj":"btn","x":10,"y":40,"w":220,"h":90,"toggle":true,"text":"\uE335","text_font":32,"mode":"break","align":1}
{"page":6,"id":24,"obj":"cpicker","x":15,"y":140,"w":140,"h":140}
{"page":6,"id":25,"obj":"slider","x":200,"y":140,"w":14,"h":140,"min":1,"max":255}

{"page":7,"Weather":"---------- Page 6 ----------"}
{"page":7,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"WEATHER","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
{"page":7,"id":2,"obj":"obj","x":5,"y":35,"w":230,"h":250,"click":0}

{"page":7,"id":14,"obj":"img","src":"L:/openhasp_dummy_img.png","parentid":2,"auto_size":1,"w":128,"offset_x":-6,"offset_y":-10}

{"page":7,"id":15,"obj":"label","x":100,"y":10,"w":130,"h":25,"align":"center","text":"date current","parentid":2}
{"page":7,"id":16,"obj":"label","x":125,"y":34,"w":95,"h":40,"align":"center","text":"00.0°C","parentid":2,"text_font":32}
{"page":7,"id":17,"obj":"label","x":110,"y":78,"w":120,"h":25,"align":"center","text":"condition","parentid":2}
{"page":7,"id":19,"obj":"label","x":90,"y":95,"w":60,"h":30,"text":"#000000 \u2022# #909090 \u2022#","parentid":2,"text_font":24,"align":"center","text_color":"grey"}

{"page":7,"id":10,"obj":"tabview","x":0,"y":0,"w":240,"h":260,"parentid":2,"btn_pos":0,"bg_opa":0,"border_width":0}
{"page":7,"id":11,"obj":"tab","parentid":10}
{"page":7,"id":12,"obj":"tab","parentid":10}

{"page":7,"id":21,"obj":"label","x":8,"y":123,"w":130,"h":22,"align":"left","text":"hour+2","parentid":11,"pad_top":3,"click":0}
{"page":7,"id":22,"obj":"label","x":124,"y":123,"w":50,"h":22,"align":"center","text":"00.0","parentid":11,"pad_top":-2,"text_font":24,"click":0}
{"page":7,"id":23,"obj":"img","x":182,"y":118,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":11,"click":0}

{"page":7,"id":31,"obj":"label","x":8,"y":154,"w":130,"h":22,"align":"left","text":"hour+3","parentid":11,"pad_top":3,"click":0}
{"page":7,"id":32,"obj":"label","x":124,"y":154,"w":50,"h":22,"align":"center","text":"00.0","parentid":11,"pad_top":-2,"text_font":24,"click":0}
{"page":7,"id":33,"obj":"img","x":182,"y":150,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":11,"click":0}

{"page":7,"id":41,"obj":"label","x":8,"y":186,"w":130,"h":22,"align":"left","text":"hour+4","parentid":11,"pad_top":3,"click":0}
{"page":7,"id":42,"obj":"label","x":124,"y":186,"w":50,"h":22,"align":"center","text":"00.0","parentid":11,"pad_top":-2,"text_font":24,"click":0}
{"page":7,"id":43,"obj":"img","x":182,"y":182,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":11,"click":0}

{"page":7,"id":51,"obj":"label","x":8,"y":218,"w":130,"h":22,"align":"left","text":"hour+5","parentid":11,"pad_top":3,"click":0}
{"page":7,"id":52,"obj":"label","x":124,"y":218,"w":50,"h":22,"align":"center","text":"00.0","parentid":11,"pad_top":-2,"text_font":24,"click":0}
{"page":7,"id":53,"obj":"img","x":182,"y":214,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":11,"click":0}

{"page":7,"id":61,"obj":"label","x":6,"y":123,"w":100,"h":22,"align":"left","text":"date+1","parentid":12,"pad_top":3,"click":0}
{"page":7,"id":62,"obj":"label","x":102,"y":123,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Navy","click":0}
{"page":7,"id":63,"obj":"label","x":150,"y":123,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Blush","click":0}
{"page":7,"id":64,"obj":"img","x":194,"y":118,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":12,"click":0}

{"page":7,"id":71,"obj":"label","x":6,"y":154,"w":100,"h":22,"align":"left","text":"date+2","parentid":12,"pad_top":3,"click":0}
{"page":7,"id":72,"obj":"label","x":102,"y":154,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Navy","click":0}
{"page":7,"id":73,"obj":"label","x":150,"y":154,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Blush","click":0}
{"page":7,"id":74,"obj":"img","x":194,"y":150,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":12,"click":0}

{"page":7,"id":81,"obj":"label","x":6,"y":186,"w":100,"h":22,"align":"left","text":"date+3","parentid":12,"pad_top":3,"click":0}
{"page":7,"id":82,"obj":"label","x":102,"y":186,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Navy","click":0}
{"page":7,"id":83,"obj":"label","x":150,"y":186,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Blush","click":0}
{"page":7,"id":84,"obj":"img","x":194,"y":182,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":12,"click":0}

{"page":7,"id":91,"obj":"label","x":6,"y":218,"w":100,"h":22,"align":"left","text":"date+4","parentid":12,"pad_top":3,"click":0}
{"page":7,"id":92,"obj":"label","x":102,"y":218,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Navy","click":0}
{"page":7,"id":93,"obj":"label","x":150,"y":218,"w":40,"h":22,"align":"center","text":"00.0","parentid":12,"pad_top":-2,"text_font":24,"text_color":"Blush","click":0}
{"page":7,"id":94,"obj":"img","x":194,"y":214,"w":32,"h":32,"src":"L:/openhasp_dummy_img.png","parentid":12,"click":0}


{"page":8,"Media Player":"---------- Page 7 ----------"}
{"page":8,"id":6,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Media Player","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
{"page":8,"id":10,"obj":"obj","x":5,"y":35,"w":230,"h":250,"click":0,"bg_opa":0,"shadow_opa":140,"shadow_color":"black","shadow_width":20,"shadow_spread":0}
{"page":8,"id":11,"obj":"obj","x":8,"y":38,"w":200,"h":84,"click":0}
{"page":8,"id":12,"obj":"label","x":10,"y":48,"w":196,"h":30,"text":"-","mode":"scroll","align":1}
{"page":8,"id":13,"obj":"label","x":10,"y":83,"w":196,"h":30,"text":"-","mode":"scroll","align":1}
{"page":8,"id":14,"obj":"bar","x":8,"y":117,"w":200,"h":5,"min":0,"max":100,"border_opa":0,"pad_top":0,"pad_bottom":0,"pad_left":0,"pad_right":0}
{"page":8,"id":15,"obj":"dropdown","x":8,"y":129,"w":120,"h":30,"options":"Source1\nSource2\nSource3","direction":3,"max_height":300,"radius":5}
{"page":8,"id":16,"obj":"dropdown","x":133,"y":129,"w":75,"h":30,"options":"Jazz\nPop\nRock","direction":2,"radius":5}
{"page":8,"id":17,"obj":"btn","x":8,"y":166,"w":50,"h":70,"toggle":false,"text":"\uE4AE","text_font":32}
{"page":8,"id":18,"obj":"btn","x":66,"y":166,"w":83,"h":70,"toggle":false,"text":"\uE40A","text_font":32}
{"page":8,"id":19,"obj":"btn","x":157,"y":166,"w":51,"h":70,"toggle":false,"text":"\uE4AD","text_font":32}
{"page":8,"id":20,"obj":"slider","x":212,"y":38,"w":20,"h":244,"min":0,"max":100,"val":85}
{"page":8,"id":21,"obj":"btn","x":8,"y":241,"w":45,"h":40,"toggle":false,"text":"\uE425","text_font":32}
{"page":8,"id":22,"obj":"btn","x":60,"y":241,"w":45,"h":40,"toggle":false,"text":"\uE457","text_font":32}
{"page":8,"id":23,"obj":"btn","x":111,"y":241,"w":45,"h":40,"toggle":false,"text":"\uE49E","text_font":32}
{"page":8,"id":24,"obj":"btn","x":163,"y":241,"w":45,"h":40,"toggle":false,"text":"\uE57E","text_font":32}


{"page":9,"Settings":"---------- Page 8 ----------"}
{"page":9,"id":6,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"Settings","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
{"page":9,"id":1,"x": 10, "y": 160,"obj":"btn","groupid":1,"toggle":true,"text":"\uE335","text_color":"#FFFFFF","radius":0,"border_side":0,"text_font":24}

{"page":9,"id":2,"x": 10, "y": 200, "obj": "btn", "action": {"hold": "restart"}, "text":"\uE456","text_color":"#FFFFFF","radius":0,"border_side":0,"text_font":24}

{"page":9,"id":3,"obj":"label","x":10,"y":250,"w":130,"h":30,"text":"Battery Level:","align":0,"text_font":16,"text_color":"#FFFFFF"}

{"page":9,"id":4,"obj":"bar","groupid":4,"x":110,"y":250,"w":130,"h":30,"align":0,"text_font":16,"text_color":"#FFFFFF","min":1,"max":255}

{"page":9,"id":5,"obj":"label","x":160,"y":250,"w":130,"h":30,"text":"%","align":0,"text_font":16,"text_color":"#FFFFFF"}


{"page":10,"Experimental":"---------- Page 9 ----------"}

{"page":10,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"COLOURED LIGHTS","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
{"page":10,"id":25,"obj":"slider","groupid":1,"x":20,"y":60,"w":40,"h":200,"min":1,"max":255, "val":1}
{"page":10,"id":26,"obj":"slider","groupid":2,"x":100,"y":60,"w":40,"h":200,"min":1,"max":255,"val":1}
{"page":10,"id":27,"obj":"slider","groupid":3,"x":180,"y":60,"w":40,"h":200,"min":1,"max":255,"val":1}

Works perfect!

1 Like

Question, My device sends voltage over MQTT, how to get it reflected in lovelace. Tried to find device among my mqtt devices, but I cant.
I have checked MQTT explorer and can see message:
image

I want to reflect battery voltage in lovelace.

Is there a sensor under the homeassistant topic?

what do you mean?

For entities to appear automatically it must be advertised under the discovery topic, which is homeassistant/

so where should I advertise it? how? my casting looks like this on the device:

String jsonString = "{\"vbat_Fraction\":" + vbatFraction + "}";
const char* jsonChar = jsonString.c_str();
dispatch_state_subtopic("vbat_Fraction", jsonChar);

Or I need to put special advertisement in MQTT settings of the device?

Yes

What I need to change so homeassistant create sensors automatically:

Looks to me OK, at the bottom it says homeassistant status, anything else needs to be changed?

no matter what I put in there still mqtt messages go as hasp, so must be something else

When you are telnetted into the device, execute the discovery command and tell us what you see. My SenseCap says

discovery
#discover[05:41:53.778][98292/109252 10][57124/57568  1] MSGR: discovery
#[05:41:59.365][98292/107664  8][57124/57568  1] MQTT PUB: discovery => {"node":"seed1","mdl":"SenseCAP Indicator D1","mf":"openHASP","hwid":"dc5475d80b2c","pages":12,"sw":"0.7.0-rc8","uri":"http://192.168.20.11","input":{"none":[38]},"power":[],"light":[],"dim":[]}

It may be that a discovery setting is not being generated for the battery.

You can always manually set up a mqtt sensor. You know where the docs are (I posted above). But it’ll be something like

# Example configuration.yaml entry
mqtt:
  - sensor:
      state_topic: "hasp/remote01/state/vbat_Level"
1 Like

Manual configuration worked! Great thanks!

I will check telnetted info once back home.
screenshot1

trying to implement deep sleep but it seems like library is not implemented in openHASP?

<command-line>: note: this is the location of the previous definition
src/custom/my_custom.cpp:13:10: fatal error: esp_deep_sleep.h: No such file or directory

UPDATE:
commented inclusion of the library leaving below code, firmware successfully compiled. Will be testing to see if it works:

void custom_loop()
{
    // read voltage every 10 seconds
    if(blink_speed && (millis() - last_blink > blink_speed)) {

        currentVoltage = analogRead(voltage_read) * (maxVoltage / 4095.0);
        // Calculate the percentage of charge
        batteryFraction = map(constrain(currentVoltage, minVoltage, maxVoltage) * 1000, minVoltage * 1000, maxVoltage * 1000, 0, 100);

        illum = analogRead(illum_read);

        if (batteryFraction <= 15) {
            low_bat_alert(LED_BUILTIN1, fadeTime);
        }
        else if (batteryFraction <= 5) {
             // Avoid rapid transitions by adding a delay
            delay(1000);  // Adjust the delay as needed           
            esp_deep_sleep(1000000LL * sleepTimeSeconds);;
        } 
        last_blink = millis();
    }
}

My remote was fully integrated to HA lovelace:
image

For the voltage readings I had to implement custom code:

my_custom.cpp:

/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
   For full license information read the LICENSE file in the project folder */

// USAGE: - Copy this file and rename it to my_custom.cpp
//        - Change false to true on line 9

#include "hasplib.h"

#if defined(HASP_USE_CUSTOM) && true // <-- set this to true in your code

#include "hasp_debug.h"
#include "custom/my_custom.h"
//#include <esp_deep_sleep.h>

unsigned long last_blink = 0;
bool blink_state = LOW;

const int LED_BUILTIN1 = 4;  //red
const int LED_BUILTIN2 = 16; //green
const int LED_BUILTIN3 = 17; //blue
const int voltage_read = 35;
const int illum_read = 34;
const int blink_speed = 10000; //read every 10sec

float batteryFraction;
float currentVoltage;
int illum;

// Implement heartbeat led
const int fadeTime = 1000; 
unsigned long lastMillis = 0;
int brightness = 0;
int fadeDirection = 1;  // 1 for fading in, -1 for fading out

//Voltage read
const int MAX_ANALOG_VAL = 4095;
const float MAX_BATTERY_VOLTAGE = 4.2; // Max LiPoly voltage of a 3.7 battery is 4.2
const float minVoltage = 3.0;  // Minimum voltage (0% charge)
const float maxVoltage = 4.2;  // Maximum voltage (100% charge)

//deep sleep timer
const int sleepTimeSeconds = 10;  // Set the sleep time in seconds

void custom_setup()
{
    // Initialization code here
    last_blink = millis();
    //pinMode(LED_BUILTIN1, OUTPUT);
    //digitalWrite(LED_BUILTIN1, LOW);
    //pinMode(LED_BUILTIN2, OUTPUT);
    //digitalWrite(LED_BUILTIN2, LOW);
    //pinMode(LED_BUILTIN3, OUTPUT);
    //digitalWrite(LED_BUILTIN3, LOW);   
    pinMode(voltage_read, INPUT);
    pinMode(illum_read, INPUT);
    randomSeed(millis());
}

void custom_loop()
{
    // read voltage every 10 seconds
    if(blink_speed && (millis() - last_blink > blink_speed)) {

        currentVoltage = analogRead(voltage_read) * (maxVoltage / 4095.0);
        // Calculate the percentage of charge
        batteryFraction = map(constrain(currentVoltage, minVoltage, maxVoltage) * 1000, minVoltage * 1000, maxVoltage * 1000, 0, 100);

        illum = analogRead(illum_read);

        if (batteryFraction <= 15) {
            low_bat_alert(LED_BUILTIN1, fadeTime);
        }
        else if (batteryFraction <= 5) {
             // Avoid rapid transitions by adding a delay
            delay(1000);  // Adjust the delay as needed           
            esp_deep_sleep(1000000LL * sleepTimeSeconds);;
        } 
        last_blink = millis();
    }
}

// Function to update the LED brightness for a heartbeat effect
void low_bat_alert(int pin, int duration) {
  unsigned long currentMillis = millis();

  // Check if it's time to update the LED brightness
  if (currentMillis - lastMillis >= duration / 255) {
    lastMillis = currentMillis;

    // Update brightness based on the fade direction
    brightness += fadeDirection;

    // Change direction if reaching maximum or minimum brightness
    if (brightness >= 255 || brightness <= 0) {
      fadeDirection *= -1;
    }

    analogWrite(pin, brightness);
  }
}

void custom_every_second()
{
    Serial.print("#");
}

void custom_every_5seconds()
{
    LOG_VERBOSE(TAG_CUSTOM, "%d seconds have passsed...", 5);


    // Convert the integer to a string
    String vbatFraction = String(batteryFraction);
    String vbatLevel = String(currentVoltage);
    String illumLevel = String(illum);

    // Create the JSON string
    String jsonString = "{\"vbat_Fraction\":" + vbatFraction + "}";
    String jsonString2 = "{\"vbat_Level\":" + vbatLevel + "}";
    String jsonString3 = "{\"illum_Level\":" + illumLevel + "}";

    

    // Convert the JSON string to a const char* for your function
    const char* jsonChar = jsonString.c_str();
    const char* jsonChar2 = jsonString2.c_str();
    const char* jsonChar3 = jsonString3.c_str();

    const char* jsonChar4 = jsonString4.c_str();

    // Call your function with the JSON string
    dispatch_state_subtopic("vbat_Fraction", jsonChar);
    dispatch_state_subtopic("vbat_Level", jsonChar2);  
    dispatch_state_subtopic("illum_Level", jsonChar3); 
    
    //Battery percentage
    String jsonString4 = "Battery"; //topic
    dispatch_state_val(jsonChar4, (hasp_event_t) 1, batteryFraction); 

}


bool custom_pin_in_use(uint8_t pin)
{
    
    switch(pin) {
        case illum_read:  // Custom LED pin
        case 6:  // Custom Input pin
            return true;
        default:
            return false;
    }
    
}

void custom_get_sensors(JsonDocument& doc)
{
    JsonObject sensor = doc.createNestedObject(F("Battery"));  // Add Key
    sensor[F("Battery")] = batteryFraction;                        // Set Value

}

void custom_topic_payload(const char* topic, const char* payload, uint8_t source){
    // Not used
}

#endif // HASP_USE_CUSTOM

Had to make voltage divider +terminal—10K—GPIO35----33K—GND

enter the following to configuration.yaml to detect correct MQTT command:

mqtt:
  - sensor:
      state_topic: "hasp/remote01/state/vbat_Level"
      name: "remote01 battery"
      json_attributes_topic: "hasp/remote01/state/vbat_Level"
      #unit_of_measurement: "V"
  - sensor:
      state_topic: "hasp/remote01/state/Battery"
      name: "remote01 battery_persentage"
      unique_id: 6d90a10e-775e-11ee-b962-0242ac120002
      json_attributes_topic: "hasp/remote01/state/Battery"
      #unit_of_measurement: "%"

sensors.yaml:

- platform: template
  sensors:
    remote01_battery_value:
      friendly_name: "Remote01 Battery percentage"
      value_template: "{{ state_attr('sensor.remote01_battery_persentage', 'val') | float }}"
      unique_id: remote01batval
      unit_of_measurement: "%"
    remote01_battery_voltage:
      friendly_name: "Remote01 Battery Voltage"
      value_template: "{{ state_attr('sensor.remote01_battery', 'vbat_Level') | float }}"
      unique_id: remote01batvol
      unit_of_measurement: "V"      

and use the following in entities card in lovelace:

type: entities
entities:
  - entity: openhasp.remote01
  - entity: switch.remote01_antiburn
  - entity: light.remote01_backlight
  - entity: light.remote01_moodlight
  - entity: number.remote01_page_number
  - entity: button.remote01_restart
  - entity: sensor.remote01_battery_value
  - entity: sensor.remote01_battery_voltage
title: Remote01
state_color: true

Now I can watch how fast openHASP device draining power off 1800Mah battery:

and nice interface:
ezgif-2-2f3b01c313

Still need to work on weather page and media player.

Further improvements

  1. to think of: usage of builtin microsd card reader to store media
  2. to implement voice control over I2S MIC and voice output over builtin amplifier to micro speaker (ordered already) iver GPIO 26 (DAC)

2 Likes

Yes but are you going to post your code for getting the screen and touch controller to work?

3 Likes