Home Assistant Community Add-on: AppDaemon 4

  1. Firstly I add serial port to my system (because it’s vitural connected via Virtual Machine eSXI), then I get new /dev/ttyUSB0 device and then when I start AD and my application I see the initialization message. Then I restart the application (by changing somecode there) or it is possible to stop AD addon → in this case I see “close” message

  2. It is USB-RS485 reader.

  3. Just the regular data, nothing special. A kind of Modbus protocol

  4. As soon as data is requested from AD

  5. yes.

  6. I use VM with DEbian Linux installed inside. VM is under eSXI solution

  7. Version supervisor-2021.04.0

import hassapi as hass
import datetime
import serial
import json
import mqttapi as mqtt
import struct
import binascii
from binascii import a2b_hex, b2a_hex

INITIAL_MODBUS = 0xFFFF
INITIAL_DF1 = 0x0000

table = (
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 )

# - mqtt topic
# - mqtt payload
# - address 0x3412 = Low byte: 34, High byte:12
###input_number.curtains_a2_1
gt_mqtt_units = [
            ["/devices/a2/curtains_1", "OPEN",  "0x0101"],
            ["/devices/a2/curtains_1", "CLOSE", "0x0101"],
            ["/devices/a2/curtains_1", "STOP",  "0x0101"],
            ["/devices/a2/curtains_1", "ADDR",  " "],            
            ["/devices/a2/curtains_2", "OPEN",  "0xFEFE"],
            ["/devices/a2/curtains_2", "CLOSE", "0xFEFE"],
            ["/devices/a2/curtains_2", "STOP",  "0xFEFE"]
           ]

gt_units = [
#---------------------------------------------------------------------------
# loggia
            ["input_number.curtains_a2_1", "0x0101"],  #0x3412
            ["input_number.curtains_a2_2", "0xFEFE"],            
#            ["input_number.curtains_a2_2", "0x0a02"]
           ]
class Context():
    serial_port = None
# REMOVED extra lines

#        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x01,0xB9,0x24); #55FEFE0301B924 
class curtain(mqtt.Mqtt, hass.Hass):
  def initialize(self):
    self.debug("Hello from AppDaemon")
    self.debug("Hello from AppDaemon ddd " + str(Context.serial_port))

    try:
      if Context.serial_port == None:
          self.debug("MQTT: -> open serial ... ")
          Context.serial_port = serial.Serial(
            port = '/dev/ttyUSB0', #/dev/ttyUSB0
            baudrate = 9600,                # 9600 bauds
            bytesize = serial.EIGHTBITS,    # 7bits
            parity = serial.PARITY_NONE,    # even parity
            stopbits = serial.STOPBITS_ONE, # 1 stop bit
            xonxoff = False,                # no flow control
            timeout = 1
            )
        
      self.debug("MQTT: -> serial is opened: " + Context.serial_port.name) 
    except Exception as e:
      self.debug("MQTT: -> open serial ERROR " + str(e))       

#    unit[0] - virtual sensor (var)
#    unit[1] - real sensor    
    for unit in gt_mqtt_units:
      # run listen      
      self.listen_event(self.mqtt_callback, 'MQTT_MESSAGE', topic=unit[0], payload=unit[1], v_addr=unit[2], namespace = "mqtt") 


    for unit in gt_units:
      # run listen      
      self.listen_state(self.callback, unit[0], addr = unit[1])


#    except Exception as e:
#        self.debug("MQTT: -> open serial ERROR ") 
#        pass

#    finally:
#        self.debug("MQTT: -> open serial ERROR ") 
#    self.ser = serial.Serial(
#        port = '/dev/ttyUSB00000', #/dev/ttyUSB0
#        baudrate = 9600,                # 9600 bauds
#        bytesize = serial.EIGHTBITS,    # 7bits
#        parity = serial.PARITY_NONE,    # even parity
#        stopbits = serial.STOPBITS_ONE, # 1 stop bit
#        xonxoff = False,                # no flow control
#        timeout = 1
#        )
    
#    self.debug("MQTT: -> open serial " + self.ser.name)

#   timer is needed to get the position
    time_1min = datetime.time(0, 0, 0) 
    self.run_minutely(self.check_pos, time_1min)

#    ser.close()
#----------------------------------------------------	
  def terminate(self):
    self.debug("MQTT: -> terminate enter ")

    if Context.serial_port != None:
        Context.serial_port.close()
        self.debug("MQTT: -> serial port closed ")
            
    self.debug("MQTT: -> terminate exit ")


  def check_pos(self, kwargs):
    
    self.debug("MQTT: timer -> get position ")

    for unit in gt_units:
#      unit[0] = input_number.curtains_a2_1
#      unit[1] = addr
      str_out = self.make_serial_out_get_position(addr = unit[1])

      self.debug("MQTT: serial out " +str(str_out))
      if Context.serial_port != None:
        if Context.serial_port.isOpen():
          Context.serial_port.write(str_out)
          Context.serial_port.flush()

          try:
              #read
              doc = Context.serial_port.readline()
              self.debug("MQTT 2. Recieved 1a:" + str(doc)) 
          except Exception as e:
              self.debug("MQTT Error : try to parse an incomplete message")
              pass

#        str_out

          str2 = struct.unpack('B B B B B B B B', doc)   
          str1 = [] 
          str1.append(struct.pack('B', str2[0]))
          str1.append(struct.pack('B', str2[1]))
          str1.append(struct.pack('B', str2[2]))
          str1.append(struct.pack('B', str2[3]))
          str1.append(struct.pack('B', str2[4]))
          str1.append(struct.pack('B', str2[5]))
#        str1.append(struct.pack('B', int('{:02x}'.format(doc[1]))))

          crc1 = calcString(str1, INITIAL_MODBUS)
          crc1_high, crc1_low = bytes(crc1)

          self.debug("MQTT 2. Recieved 1b:" + str(str2)) 
          self.debug("MQTT 2. Recieved 1c:" + str(str2[5])) 

          if ( crc1_low == '0x{:02x}'.format(str2[6]) and
              crc1_high == '0x{:02x}'.format(str2[7]) ):
        
            self.debug("MQTT CRC OK:")

          position = int('0x{:02x}'.format(doc[5]),16)
        #doc[5] просто в int значение
#        self.call_service("input_number/set_value", entity_id = unit[0], value = position)     
          self.call_service("input_number/set_value", entity_id = unit[0], value = position)     
#        self.set_value(unit[0], position)
          self.debug("MQTT 2. set_value:" + str(unit[0]) + " " + str(position)) 
          self.debug("MQTT 2. Recieved:" + str(position))

        else:
          self.debug("MQTT: Error - serial closed ")

#----------------------------------------------------
  def callback(self, entity, attribute, old, new, kwargs):

    addr_high, addr_low = bytes(int(kwargs.get('addr'),16))

    if isInt(int(float(self.get_state(entity)))):

      self.debug("MQTT: Position" + str(int(float(self.get_state(entity)))))

      position = hex(int(float(self.get_state(entity))))
      command = '0x04'
      
      str_out = self.make_serial_out(addr = kwargs.get('addr'), command = command, data = position)
#      command = '0x01'
#      str_out = self.make_serial_out(addr = kwargs.get('addr'), command = command, data = "")

      self.debug("MQTT: serial out " +str(str_out))
      if Context.serial_port.isOpen():
        Context.serial_port.write(str_out)
        Context.serial_port.flush()

        try:
            #read
            doc = Context.serial_port.readline()
            self.debug("MQTT: Position Recieved 1a:" + str(doc)) 
        except Exception as e:
            self.debug("MQTT Error : try to parse an incomplete message")
            pass

      else:
        self.debug("MQTT: Error - serial closed")

    else:
      self.debug("MQTT: Position is not int" + self.get_state(entity))

#----------------------------------------------------
  def mqtt_callback(self, event_name, data, kwargs): #data, kwargs): #self, event_name, *args, **kwargs):


    payload = kwargs.get('payload')
    self.debug("MQTT-mqtt_callback: Command ")

    if payload == 'OPEN':
      addr_high, addr_low = bytes(int(kwargs.get('v_addr'),16))
      command = '0x01'
      str_out = self.make_serial_out(addr = kwargs.get('v_addr'), command = command, data = "")


    elif payload == 'CLOSE':
      addr_high, addr_low = bytes(int(kwargs.get('v_addr'),16))
      command = '0x02'
      str_out = self.make_serial_out(addr = kwargs.get('v_addr'), command = command, data = "")
    elif payload == 'STOP':
      addr_high, addr_low = bytes(int(kwargs.get('v_addr'),16))
      command = '0x03'
      str_out = self.make_serial_out(addr = kwargs.get('v_addr'), command = command, data = "")
    elif payload == 'ADDR':
#      self.check_pos(self)
      command = ''
      str_out = self.make_serial_out_set_addr(addr_curr = "0x0000", addr = self.get_state('input_text.curtains_new_addr'))

    self.debug("MQTT: Command " + command)
    


    self.debug("MQTT: serial out " + str(str_out))
    if Context.serial_port.isOpen():
      Context.serial_port.write(str_out)
      try:
            #read
          doc = Context.serial_port.readline()
          self.debug("MQTT-mqtt_callback: Command Recieved 1a:" + str(doc)) 
      except Exception as e:
          self.debug("MQTT Error : try to parse an incomplete message")
          pass      
      Context.serial_port.flush()
    else: 
      self.debug("MQTT: Error - serial closed ")

#--------------------------------------------------------
# compose serial string | commands: OPEN CLOSE STOP 
#--------------------------------------------------------
  def make_serial_out(self, **kwargs):

      command = kwargs.get('command')
      data = kwargs.get('data')

      addr_high, addr_low = bytes(int(kwargs.get('addr'),16))
      str1 = [] 
      str1.append(struct.pack('B', int('0x55',16)))
      str1.append(struct.pack('B', int(addr_low,16)))
      str1.append(struct.pack('B', int(addr_high,16)))
      str1.append(struct.pack('B', int('0x03',16)))
      str1.append(struct.pack('B', int(command,16)))
      if data != "":
        str1.append(struct.pack('B', int(data,16)))
      
      crc1 = calcString(str1, INITIAL_MODBUS)
      crc1_high, crc1_low = bytes(crc1)
      str1.append(struct.pack('B', int(crc1_low,16)))
      str1.append(struct.pack('B', int(crc1_high,16)))

      if data != "":
        str_out = struct.pack('B B B B B B B B', 
                int('0x55',16),
                int(addr_low,16),
                int(addr_high,16),
                int('0x03',16),
                int(command,16),
                int(data,16),
                int(crc1_low,16),
                int(crc1_high,16))
      else:
        str_out = struct.pack('B B B B B B B', 
                int('0x55',16),
                int(addr_low,16),
                int(addr_high,16),
                int('0x03',16),
                int(command,16),
                int(crc1_low,16),
                int(crc1_high,16))    
    
      return str_out

#--------------------------------------------------------
# compose serial string | command: set new address
#--------------------------------------------------------
  def make_serial_out_set_addr(self, **kwargs):

      addr_high, addr_low = bytes(int(kwargs.get('addr_curr'),16))
      addr_n_high, addr_n_low = bytes(int(kwargs.get('addr'),16))

      str1 = [] 
      str1.append(struct.pack('B', int('0x55',16)))
      str1.append(struct.pack('B', int(addr_low,16)))
      str1.append(struct.pack('B', int(addr_high,16)))
      str1.append(struct.pack('B', int('0x02',16)))
      str1.append(struct.pack('B', int('0x00',16)))      
      str1.append(struct.pack('B', int('0x02',16)))            
      str1.append(struct.pack('B', int(addr_n_low,16)))
      str1.append(struct.pack('B', int(addr_n_high,16)))
      crc1 = calcString(str1, INITIAL_MODBUS)
      crc1_high, crc1_low = bytes(crc1)
      str1.append(struct.pack('B', int(crc1_low,16)))
      str1.append(struct.pack('B', int(crc1_high,16)))

      str_out = struct.pack('B B B B B B B B B B', 
                int('0x55',16),
                int(addr_low,16),
                int(addr_high,16),
                int('0x02',16),
                int('0x00',16),
                int('0x02',16), 
                int(addr_n_low,16),
                int(addr_n_high,16),                                               
                int(crc1_low,16),
                int(crc1_high,16))      
                
      return str_out
#--------------------------------------------------------
# compose serial string
#--------------------------------------------------------
  def make_serial_out_get_position(self, **kwargs):

      addr_high, addr_low = bytes(int(kwargs.get('addr'),16))
      str1 = [] 
      str1.append(struct.pack('B', int('0x55',16)))
      str1.append(struct.pack('B', int(addr_low,16)))
      str1.append(struct.pack('B', int(addr_high,16)))
      str1.append(struct.pack('B', int('0x01',16)))
      str1.append(struct.pack('B', int('0x02',16)))
      str1.append(struct.pack('B', int('0x01',16)))

      crc1 = calcString(str1, INITIAL_MODBUS)
      crc1_high, crc1_low = bytes(crc1)
      str1.append(struct.pack('B', int(crc1_low,16)))
      str1.append(struct.pack('B', int(crc1_high,16)))

      str_out = struct.pack('B B B B B B B B', 
                int('0x55',16),
                int(addr_low,16),
                int(addr_high,16),
                int('0x01',16),
                int('0x02',16),
                int('0x01',16),                                
                int(crc1_low,16),
                int(crc1_high,16))      
                
      return str_out

#--------------------------------------------------------
  def do_process (self, entity, attribute, old, new, kwargs):

    clicks = '1'
    Context.serial_port.write(bytes(clicks.encode('ascii')))
    buffer = ""
    
    while True:
        try:
                buffer = ser.readline()
                self.log(buffer)
                doc = json.loads(buffer)
    
                read_b1 = doc["b1"]
                read_b2 = doc["b2"]
    
                read_s1 = doc["s1"]
                read_s2 = doc["s2"]
                
                self.log(read_b1)
                buffer = ""
        except json.JSONDecodeError:
                self.log("Error : try to parse an incomplete message")    

#----------------------------------------------------
  def debug(self, text):
    if self.args["DEBUG"] == 1:
      self.log("Curtain " + text)
#----------------------------------------------------     
def isInt(value):
  try:
    int(value)
    return True
  except ValueError:
    return False
  except TypeError:
    return False    

def calcByte( ch, crc):
    #Given a new Byte and previous CRC, Calc a new CRC-16"""
    if type(ch) == type("c"):
        by = ord(ch)
    else:
        by = ch
    crc = (crc >> 8) ^ table[(crc ^ by) & 0xFF]
    return (crc & 0xFFFF)

def calcString(st, crc):
    #Given a bunary string and starting CRC, Calc a final CRC-16 """
    for ch in st:
        crc = (crc >> 8) ^ table[(crc ^ ord(ch)) & 0xFF]
    return crc    

def bytes(num):
    return hex(num >> 8), hex(num & 0xFF)    

def ascii_to_packed_hex(string_data): 
    # convert each pair of hex digits in the string into an integer
    # then convert those to characters and join them into a string
    return ''.join(chr(int(digits, 16)) for digits in 
                (string_data[x:x+2] for x in range(0, len(string_data), 2)))    

def decode_int(num):
    # remove 0x at the start
    dec = hex(num)[2:]
    # if num is long hex() will add L at the end
    dec = dec.replace("L", "", 1)
    if len(dec) % 2 == 1:
        dec = "0" + dec
    return a2b_hex(dec)                


#v_sensor = kwargs.get('v_sensor')
#    aaa = bytes.fromhex('01')

#    self.debug("MQTT: HEX    " +str(ascii_to_packed_hex('55')))

#    ppp = decode_int('\x55')
#    self.debug("MQTT: st1    " +str(ppp))

#    st = "\x55" + "\x12\x34" + "\x03" + "\x04" + "\x32"
#55 - фиксированный префикс
#12 34  - адрес устройства 
#03 - отправить команду
#04 - положение карниза
#32 - число 50 в hex
#С9 38 - CRC16/modbus с обратным расположением байтов

#    crc = calcString(st, INITIAL_MODBUS)
#    crc_high, crc_low = bytes(crc)
    #addr_high, addr_low = bytes(int(kwargs.get('v_addr'),16))
    ##position = hex(int(float(self.get_state(entity))))
    #command = '0x04'

#    aaa = []
#    aaa.append(ascii_to_packed_hex('55'))
#    aaa.append(ascii_to_packed_hex('aa'))
#    aaa.append(ascii_to_packed_hex('01'))
#    self.debug("MQTT: HEX    " +str(aaa))
#    self.debug("MQTT: st    " +st)
    

#    str1 = struct.pack('B B B B B B B B',
#      int('0x55',16), 
#      int(addr_low,16), 
#      int(addr_high,16),
#      int('0x03',16),
#      int('0x04',16),       
#      int(position,16), 
#      int(crc_low,16),
#      int(crc_high,16)) 

#    aaa1 = []
    #aaa1.append(ascii_to_packed_hex(int('0x55',16)))
    #byte_body = binascii.a2b_hex(struct.pack('B',int('0x55',16)))
#    hexadecimal_string = "55"
#    byte_array = bytearray.fromhex(hexadecimal_string)

#    self.debug("MQTT: byte_body    " +str(byte_array))

#    self.debug("MQTT: st11111    " +str(crc1_high) + " " + str(crc1_low))    
#    self.debug("MQTT: st222    " +str(str2))        
#    #str1 = struct.pack('H H H H H H H', '55', addr_low, addr_high, '3', position, crc_low, crc_high) 
#    self.ser.write(b'hello')
#    self.debug("MQTT: crc" + str(crc_low) + " " + str(crc_high))
#    self.debug("MQTT: addr" + str(addr_low) + " " + str(addr_high))
#    self.debug("MQTT: pos" + str(position))
#    self.debug("MQTT: str1 " +str(str2))
#    if ser.isOpen():
#send data
#        ser.write(data)
#        ser.flush()
#        try:
#            #read
#            doc = ser.readline()
#            self.log(2)
#        except Exception as e:
#            self.log("Error : try to parse an incomplete message")
#            pass

#      ser.close()
#      doc = json.loads(doc)
#      self.log("2. Recieved: %s\n",doc)
#    str1 = [] 
#    str1.append(struct.pack('B', int('0x55',16)))
#    str1.append(struct.pack('B', int(addr_low,16)))
#    str1.append(struct.pack('B', int(addr_high,16)))
#    str1.append(struct.pack('B', int('0x03',16)))
#    str1.append(struct.pack('B', int(command,16)))
#    crc1 = calcString(str1, INITIAL_MODBUS)
#    crc1_high, crc1_low = bytes(crc1)
#    str1.append(struct.pack('B', int(crc1_low,16)))
#    str1.append(struct.pack('B', int(crc1_high,16)))

#    str_out = struct.pack('B B B B B B B', 
#                int('0x55',16),
###                int(addr_low,16),
#                int(addr_high,16),
#                int('0x03',16),
##                int(command,16),
#                int(crc1_low,16),
#                int(crc1_high,16))
#    if ser.isOpen():
#send data
#        ser.write(data)
#        ser.flush()
#        try:
#            #read
#            doc = ser.readline()
#            self.log(2)
#        except Exception as e:
#            self.log("Error : try to parse an incomplete message")
#            pass

#      ser.close()
#      doc = json.loads(doc)
#      self.log("2. Recieved: %s\n",doc)

 #   else:
 #     self.debug("MQTT: not Int " + self.get_state(entity))

there is a lot in the code that i see what can cause trouble. but also i believe a lot of obsolete stuff.
i just took a glance at it, but to little to find the problem that causes your issues.

when you come to our discord ill take the time to go through stuff with you. that would take up to much overhere.

I am there. Ok. i will post my code there

Even though it’s in spanish, I think it could be helpful the examples used here to see the advantages to use appdaemon for some automations in Home Assistant: Cómo usar AppDaemon en Home Assistant - Paciencia Digital. Domótica, Estadística y Datos

Hi, I have a noob question, can you using AppDaemon use this API: AirMusic to control my internet radios via media_control card in lovelace?

I’m trying to integrate my internet radios with HA, but I have absolutely no programing skills :wink:

yes its possible, but completely without programming skills its not going to be easy.
youll need to learn a lot for it.

Hi.
I am trying to send commands to the IC MCP2200 (usb HID), my computer has Hassio and AppDaemon 4, my configuration:
config_appdaemon

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Control IC MCP2200 USB-HID.

import appdaemon.plugins.hass.hassapi as hass
import usb
import usb.core
import usb.util
import usb.backend.libusb1

import sys
import os
#import asyncio
import queue

commands = queue.Queue()

class Context:
    dev_usb_hid = None
# -------------------------------------------------------
class UsbRelay (hass.Hass): 
    def initialize(self):
        self.connect_usb_hid()
        
    # -------------------------------------------------------
    def connect_usb_hid(self):
        connected = False
        while not connected:
            if Context.dev_usb_hid == None:
                self.debug("Ini. USB-HID ... ")
                if hasattr(usb, 'version_info'):
                    self.debug("Version pyusb: " + str (usb.version_info))
                backend =  usb.backend.libusb1.get_backend()
                self.debug('Backend: ' + str (backend))
                if backend is None:
                    self.debug("Error usb-libusb!!")
                else:
                    dev_usb_hid = usb.core.find(idVendor=0x04d8, idProduct=0x00df, backend=backend)
                    if dev_usb_hid is None:
                        self.debug("No MCP2200!!")
                        connected = False
                    else:
                        self.debug("OK MCP2200")
                        connected = True
                       
                        for dev in dev_usb_hid:
                            serial_num = usb.util.get_string(dev,dev.iSerialNumber)
                        if dev.is_kernel_driver_active(2):
                            dev.detach_kernel_driver(2)
                            usb.util.claim_interface(dev, 2)
                        HID_INTERFACE = self.args["MCP2200_HID_INTERFACE"]
                        endpoint = dev_usb_hid[0][(HID_INTERFACE,0)][1]
                        self.debug('Endpoint: \n' + str (endpoint))
                        inipoint = dev_usb_hid[0][(HID_INTERFACE,0)][0]
                        self.debug('Inipoint: \n' + str (inipoint))

                        get_status_cmd = [0x80] + [0]*15
                        cfg_cmd = [0x10] + [0]*15
                        cfg_cmd[6] = 0xc3 #defecto GPIOS bitmap->11000011
                        cfg_cmd[9] =0x67 # 115200bps ->103
                        
                        dev.write(endpoint.bEndpointAddress, get_status_cmd)
                        self.debug('RX Config. NVRAM: ' + str (resp))
                        continue
            if not connected:
                asyncio.sleep(2)
    # ----------------------------------------------------
    def terminate(self):
        if Context.dev_usb_hid != None:
            Context.dev_usb_hid.close()
    # ----------------------------------------------------
    def debug(self, text):
        if self.args["DEBUG"] == 1:
            self.log('DEBUG: ' + text)   

I obtain this result:

2022-10-09 12:37:50.095833 INFO usb-hdi_relay: DEBUG: Ini. USB-HID ...  
2022-10-09 12:37:50.098047 INFO usb-hdi_relay: DEBUG: Version pyusb: (1, 2, 1)
2022-10-09 12:37:50.117884 INFO usb-hdi_relay: DEBUG: Backend:  <usb.backend.libusb1._LibUSB object at 0x7fb1b2008f70>
2022-10-09 12:37:50.121085 INFO usb-hdi_relay: DEBUG: OK MCP2200
2022-10-09 12:37:50.123755 WARNING usb-hdi_relay: ------------------------------------------------------------
2022-10-09 12:37:50.124689 WARNING usb-hdi_relay: Unexpected error running initialize() for usb-hdi_relay
2022-10-09 12:37:50.125243 WARNING usb-hdi_relay: ------------------------------------------------------------
2022-10-09 12:37:50.127767 WARNING usb-hdi_relay: Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/appdaemon/app_management.py", line 165, in initialize_app
    await utils.run_in_executor(self, init)
  File "/usr/lib/python3.10/site-packages/appdaemon/utils.py", line 337, in run_in_executor
    response = future.result()
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/appdaemon/apps/usb_relay_1.py", line 30, in initialize
    self.connect_usb_hid()
  File "/config/appdaemon/apps/usb_relay_1.py", line 89, in connect_usb_hid
    serial_num = usb.util.get_string(dev_usb_hid,3)
  File "/usr/lib/python3.10/site-packages/usb/util.py", line 313, in get_string
    raise ValueError("The device has no langid"
ValueError: The device has no langid (permission issue, no string descriptors supported or device error)
2022-10-09 12:37:50.130290 WARNING usb-hdi_relay: -----------------------------------------------------------

do you know how to solve it? Thanks

i dont know what data is in dev_usb_hid
but this command goes wrong:

serial_num = usb.util.get_string(dev,dev.iSerialNumber)

but that doesnt matter at all, because when it would go right, AD would never start, because you cant use a while loop in an initialise.
AD would never be able to finish starting after that loop starts running.

i think you can better find help on the HA discord.

HI, the problem i think is a permissions problem, if i check the obtained in:
dev_usb_hid = usb.core.find(idVendor=0x04d8, idProduct=0x00df, backend=backend)

cap_appdaemon

I created a file with this rule:ATTRS{idVendor}==“04d8”, ATTRS{idProduct}==“00df”, GROUP:=“daemon”, MODE=“0660” (pendrive-USB->CONFIG/udev/50-mcp2200.rules), but it does not solve the problem. Thanks

Just started using Appdaemon plugin :grinning: couple of quick questions (using HA OS)

a) does it try to download Python dependencies after each restart (or maybe that’s just what it looks like in the logs)

b) is there a log path if I wanted to tail the after an Appdaemon restart? Rather than using the web tab

c) if there’s a Python package it doesn’t find (that I’ve used elsewhere in the past) is there a way to load this? Or should I look for another similar Python package that can be found? Eg xml.etree.ElementTree

Hi all.
Someone noticed that doing a “reload template” (service Template entities) from home assistant, in appDaemon the template entities (sensor, select etc) return none for 5-6 minutes (as if they were frozen)
Restarting the addon returns everything to normal until the Template entities service is run again.

What’s the “right way” to configure the MQTT broker hostname, when adding the MQTT plugin configuration to this add-on?

If I used 127.0.0.1 or localhost it fails to connect. I’m running the core mosquitto add-on on HaOS.

If I put my fully qualified hostname into the config file it does work, but wondering if there is a better way.

Anyone have any idea why my python scripts can no longer detect dependencies installed by AppDaemon? This used to work, but now it doesn’t. I tried rolling back AppDaemon to v0.7.x, but the result is the same so maybe something changed in how the HA system python interacts with AppDaemon? Where does AppDaemon install python packages to?

More details of my issue:

Version 0.14.0 has a breaking change: “Drop support for armhf & i386”.

This has a scary ring to it: Two of my HA instances are running on PCs (one Intel NUC with an i5 processor running HA Supervised, and one old laptop with an i7 processor running HA OS).

Does the “drop support” mean what it sounds like: That I shouldn’t upgrade to 0.14.0 on these two instances. (I noticed the same for the Z-Wave JS UI upgrade and for the Node-Red upgrade.)

Ah, i386 is 32-bit, while x86-64 (which I using) is 64-bit. So I need not worry, I guess.

1 Like

I see this message when I start appdaemon after update to 0.15.2

[07:07:06] INFO: Starting AppDaemon...
s6-rc: info: service legacy-services successfully started
Traceback (most recent call last):
  File "/usr/bin/appdaemon", line 8, in <module>
ERROR Error loading secrets file: /config/secrets.yaml
    sys.exit(main())
             ^^^^^^
  File "/usr/lib/python3.11/site-packages/appdaemon/__main__.py", line 417, in main
    admain.main()
  File "/usr/lib/python3.11/site-packages/appdaemon/__main__.py", line 276, in main
    if "appdaemon" not in config:
       ^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable
[07:07:09] INFO: Service AppDaemon exited with code 1 (by signal 0)

Any ideas on how to fix this?

Hmm, just found the secrets discussion on github, so I went to fix it, all my config under appdaemon is gone???

This is probably the thread you’re looking for…

No. it’s all moved to new folder. You need to edit appdaemon.yaml file located in hassio folder. Take a look here: https://github.com/hassio-addons/addon-appdaemon/issues/287#issuecomment-1817491539

EDIT :
Turns out this WAS a stupid question, as the package in question has nothing to do with AppDaemon but was actually in my AppDaemon config as a “System package” for… reasons that probably make sense to the me of over a year ago but are lost to the sands of time. So totally my fault, leaving this up merely to shame myself.

I feel like this is going to be a stupid question but : anyone ever gotten this message? I updated to 0.16.0 this morning and AppDaemon won’t start, the log seems to say that i’ts having trouble finding the chromium-chromedriver package. I assume that all happens under the covers so not sure what I should do to fix it. Running HA-OS on a RPi 4b.

Executing fontconfig-2.14.2-r4.trigger
OK: 121 MiB in 104 packages
ERROR: unable to select packages:
  chromium-chromedriver (no such package):
    required by: world[chromium-chromedriver]
[16:14:22] FATAL: Failed installing package chromium-chromedriver
s6-rc: warning: unable to start service init-appdaemon: command exited 1
/run/s6/basedir/scripts/rc.init: warning: s6-rc failed to properly bring all the services up! Check your logs (in /run/uncaught-logs/current if you have in-container logging) for more information.
/run/s6/basedir/scripts/rc.init: fatal: stopping the container.
s6-rc: info: service legacy-cont-init: stopping