AppDaemon Q&A

I was just working with it last night. I have an app that based on HA group membership, finds all the entities, even if they are in sub groups and depending on what device type they are either turns them off or closes them after 5 minutes (configurable via appdeamon.cfg) but only if it’s after a certain time at night (that time is read from 2 input_sliders in HA). But the trick was I couldn’t just use turn_off because I have two garage doors so I needed to call the correct service for it to close.

Thank goodness you were having trouble that bailed me out! :wink:

Do share what you made I would like to see how I can rinse and repeat it. If anyone cares about what I did here it is.

Using MySensors Scene controller with 4 button like this: https://forum.mysensors.org/topic/2001/how-to-make-a-simple-cheap-scene-controller-with-video
slight change of code to work via 2.0 library and HA as 1 sensor

#define MY_DEBUG
#define MY_RADIO_NRF24
#define MY_OTA_FIRMWARE_FEATURE

#include <SPI.h>
#include <MySensors.h>
#include <Keypad.h>

#define NODE_ID AUTO // or set to AUTO if you want gw to assign a NODE_ID for you.
#define SN "Scene Controller"
#define SV "2.0"
#define KEYPAD_CHILD_ID 95

MyMessage scene(KEYPAD_CHILD_ID, V_SCENE_ON); //scene ON
//MyMessage scene2(KEYPAD_CHILD_ID, V_SCENE_OFF); //scene OFF

const byte ROWS = 4; //four rows
const byte COLS = 1; //one column
char keys[ROWS][COLS] = {
  {'1'},
  {'2'},
  {'3'},
  {'4'}
};

byte rowPins[ROWS] = {6, 7, 4, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
byte lastState;


void setup() {
  
  sendSketchInfo(SN, SV);
  present(KEYPAD_CHILD_ID, S_SCENE_CONTROLLER);
  keypad.addEventListener(keypadEvent);
}

void loop() {
  char key = keypad.getKey();
}

void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {

    case PRESSED:
      lastState = 1;
      break;

    case HOLD:
      lastState = 2;
      break;

    case RELEASED:
      int keyInt = key - '0'; //Quick way to convert Char to Int so it can be sent to controller
      if (lastState == 2) {
        keyInt = keyInt * 10; //If button is held, add 4.  If using more than 4 buttons this number will need to be changed
//        send(scene2.set(keyInt));  // this is sending the buttons to HA as 2 seperate  Devices/Sensors
        send(scene.set(keyInt));
      } else {
      send(scene.set(keyInt));
      }
      break;
 }
}

Config stuff

# [office_4_button]
# module = mys_4_button
# class = Mys4Button
# sensor = sensor.scene_controller_1_95
# entity_1 = group.office
# stat1 = switch/turn_on
# entity_2 = 
# stat2 = 
# entity_3 =
# stat3 = 
# entity_4 =
# stat4 = 
# entity_10 = group.office
# stat10 = switch/turn_off
# entity_20 =
# stat20 = 
# entity_30 =
# stat30 = 
# entity_40 = group.office
# stat40 = 

Then the App stuff


import appdaemon.appapi as appapi

class Mys4Button(appapi.AppDaemon):


  def initialize(self):
    
    self.handle = None
    
    # Check some Params

    # Subscribe to sensors
    if "sensor" in self.args:
      self.listen_state(self.motion, self.args["sensor"])
    else:
      self.log("No sensor specified, doing nothing")
    
  def motion(self, entity, attribute, old, new, kwargs):
    if new == "1":
      if "entity_1" in self.args:
        self.log("Button 1 Pressed Action for {} ".format(self.args["entity_1"]))
#        self.turn_on(self.args["entity_1"])

# Short presses are 1-4 Long Press is *10 so 10-40

        self.call_service(self.args["stat1"], entity_id = self.args["entity_1"])

    if new == "2":
      if "entity_2" in self.args:
        self.log("Button 2 Pressed Action for {} ".format(self.args["entity_2"]))
        self.call_service(self.args["stat2"], entity_id = self.args["entity_2"])

    if new == "3":
      if "entity_3" in self.args:
        self.log("Button 3 Pressed Action for {} ".format(self.args["entity_3"]))
        self.call_service(self.args["stat3"], entity_id = self.args["entity_3"])

    if new == "4":
      if "entity_4" in self.args:
        self.log("Button 4 Pressed Action for {} ".format(self.args["entity_4"]))
        self.call_service(self.args["stat4"], entity_id = self.args["entity_4"])

    if new == "10":
      if "entity_10" in self.args:
        self.log("Button 10 Pressed Action for {} ".format(self.args["entity_10"]))
        self.call_service(self.args["stat10"], entity_id = self.args["entity_10"])

    if new == "20":
      if "entity_20" in self.args:
        self.log("Button 20 Pressed: Action for {} ".format(self.args["entity_20"]))
        self.call_service(self.args["stat20"], entity_id = self.args["entity_20"])


    if new == "30":
      if "entity_30" in self.args:
        self.log("Button 30 Pressed Action for {} ".format(self.args["entity_30"]))
        self.call_service(self.args["stat30"], entity_id = self.args["entity_30"])


    if new == "40":
      if "entity_40" in self.args:
        self.log("Button 40 Pressed Action for {} ".format(self.args["entity_40"]))
        self.call_service(self.args["stat40"], entity_id = self.args["entity_40"])

                        
                        
  def motion(self, entity, attribute, old, new, kwargs):

    if new == "1" or new == "2" or new == "3" or new == "4" or new == "10" or new == "20" or new == "30" or new == "40":
        self.log("Button "+new+" Pressed Action for {} ".format(self.args["entity_"+ new]))
        self.call_service(self.args["stat" + new], entity_id = self.args["entity_" + new])

if new in ["1","2","3","4","10","20","30","40"]:
  self.log("Button "+new+" Pressed Action for {} ".format(self.args["entity_"+ new]))
  self.call_service(self.args["stat" + new], entity_id = self.args["entity_" + new])

should work too. :slight_smile:

How about this… I’m at work, not at home so I haven’t tested this.

in your appdaemon.cfg

entities={“1”:{“button”:”Button_1”,”entity”:”entity_1”},
          “2”:(“button”:”button_2”,”entity”:”entity_2”},
          “3”:(“button”:”button_3”,”entity”:”entity_3”},
          “4”:(“button”:”button_4”,”entity”:”entity_4”},
          “10”:(“button”:”button_10”,”entity”:”entity_10”},
          “20”:(“button”:”button_20”,”entity”:”entity_20”},
          “30”:(“button”:”button_30”,”entity”:”entity_30”},
          “40”:(“button”:”button_40”,”entity”:”entity_40”}}

then in your code

entities=eval(self.args[“entities”])
if new in entities
  self.log(“{} Pressed Action for {} “.format(entities[new][“button”],entities[new][“entity”]))
  self.service(entities[new][“button”],entity_id=entities[new][“entity”])

Cool Worked! Much smaller

@turboc you where making it less complicated then throw me a curve ball! :slight_smile:

Yea,
That was me having fun with Rene.

He’s a good guy and knows a lot.

it wouldnt work but it would be the wrong way for most people :wink:

if you know in advantage that your entities all have the same name with only a figure changing it wouldnt be wise to take it to the config. unless you want to give the code to someone who wants the same thing with different entity names.

now why it wouldnt work:

with this code you would try to start the service “button_1” with entity “entity_1”
and that is an unknown service in HA :wink:

i am by the way also no fan of using dictionaries in configfiles.
configfiles should be easy to read and dict make them to much “code”

in the case from @DrJeff i would probably change things in the config to something like:

sensor = sensor.scene_controller_1_95
switch1 = group.office
switch2 = 
switch3 =
switch4 =  

and in the code to:

import appdaemon.appapi as appapi

class Mys4Button(appapi.AppDaemon):

  def initialize(self):
    
    if "sensor" in self.args:
      self.listen_state(self.motion, self.args["sensor"])
    else:
      self.log("No sensor specified, doing nothing")

  def motion(self, entity, attribute, old, new, kwargs):

    self.log("Button " + new + " Pressed ")
    if "0" in new:
      self.turn_off( self.args["switch" + new[1]])
    else:
      self.turn_on( self.args["switch" + new[1]])

nothing complicated, everything in the config that should be in the config, usable for all, readable config, with as little redundantie as possible without compromising the readability.

the last redundatie (switch1, switch2,etc) could be taken away and in the config it could give:

switches = group.office,

but then the combination from switch 1 to the entity connected to it wouldnt be visible.

by the way, i dont know a lot, i just know how to keep up that appearance :wink:

Don’t believe that for a minute.

2 Likes

still its true that i dont know half of the things people suspect me to know.
but i really know how to search (and splitt valuable from unvaluable info), i have a decent memory and have a kind of logic that is strange to a lot of people :wink:

You and me both on that case. But you still know more than you let on. Your code shows that.

That’s the key to looking smart - it is a good skill to have. Basically, as long as you are one page ahead in the book and know how to learn fast and find things out quickly you can pretend to be a genius most of the time :slight_smile:

1 Like

Until recently, I built an entire career on that proposition.

3 Likes

i already told rob that there must be reason why we 3 connect so good together.

andrew well said. i will use it again on another time and another place :wink:

2 Likes

Plus we’re all devastatingly charming.

1 Like

And don;t forget handsome!

1 Like

to bad for you 2 that i am the only real handsome one :stuck_out_tongue:

LOL - that makes you the clear winner Rene!

i just took a second longer to search :wink:

1 Like

i just thought about all those people who have this topic in there watchlist.
would they dare ask another question after all this? :wink:

I was being generous about myself for Rene’s benefit. As I am the only one of the three here who lives alone, I’m not as charming as I pretend to be online.