App stops working or crashes, Appdaemon needs restart

This is my first app and first time doing something in Python

I have a servo to open and close a chicken door, the servo is much to fast. So this app slows down the servo.

The app works a short time and then nothing. Sometimes I can execute the App twice sometimes only once, after restarting AppDaemon the app works again.

import appdaemon.plugins.hass.hassapi as hass
import paho.mqtt.client as mqtt
import time
import os
import urllib.request

domainTopic = "esp22"                                           # name for the first topic                  domainTopic/####
targetvalueTopic = "value"                                      # topicname for target Value                domainTopic/value
lastValueTopic = "actualValue"                                  # topicname for last Value send to Servo    domainTopic/actualValue
stateTopic = "state"                                            # topicname for state open/close

class Slowservo(hass.Hass):
    def initialize(self):
        global minValue
        global maxValue
        mqttHost = ""                            # mqtt IP Adress
        mqttUsername="username"                                  # mqtt username
        mqttPassword="password"                                  # mqtt password
        __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
                                                                # local python script path
        fmin = open(os.path.join(__location__,"minValue.txt"), "r")
                                                                # open file for minValue
        minValue = int(                             # read and save smallest Value = open
        fmax = open(os.path.join(__location__,"maxValue.txt"), "r")
                                                                # open file for maxValue
        maxValue = int(                             # read and save largest Value = close

        self.log("### Slowservo started ###")                   # Appdaemon log entry Slowservo started
        self.log(str(minValue))                    # Appdaemon log entry min Value
        self.log(str(maxValue))                   # Appdaemon log entry max Value

        client = mqtt.Client()                                  # instance
        client.on_connect = self.on_connect                     # on copnnect instance callback
        client.on_message = self.on_message                     # on message instance callback
        client.username_pw_set(mqttUsername,mqttPassword)       # set user and password
        client.connect(mqttHost, 1883, 60)                      # connect to server with ip, port
        client.loop_forever()                                   # loop

    def on_connect(self, client, userdata, flags, rc):          # callback for mqtt connection
        client.subscribe(domainTopic +"/" +targetvalueTopic)       # mqtt topic subscribe for new Servo value

    def on_message(self, client, userdata, msg):                # callback when receiving message
        global minValue
        global maxValue
        __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
                                                                # local python script path
        f = open(os.path.join(__location__,"textfile.txt"), "r")
                                                                # open file for actualValue
        actualValue = int(                               # read and save actualValue

        targetValue = int(msg.payload.decode("utf-8"))          # Decoding UTF-8 string and typecasting to int and saving targetValue
        if (targetValue <= maxValue and targetValue >= minValue):
                                                                # check if targetValue is in range of possible Values
            while targetValue != actualValue:                   # while loop as long actual value is not target value
                if targetValue > actualValue:                   # closing the door
                    actualValue = actualValue + 1               # next value step = 1
                elif targetValue < actualValue:                 # opening the door
                    actualValue = actualValue - 1               # next value step = 1
                self.log(str(actualValue))                      # Appdaemon log for actual value
                                                                # Rest get link for command the servo new value
                f = open(os.path.join(__location__,"textfile.txt"), "w")
                                                                # open file to save actual position of servo
                f.write(str(actualValue))                       # write file to save actual position of servo
                f.close()                                       # close file to flush
                client.publish(domainTopic +"/" +lastValueTopic, str(actualValue))
                                                                # only for debugging, post actual value to mqtt
                client.loop()                                   # for post actual value to mqtt
                time.sleep(0.01)                                # sleep to slow down servo
            self.log("### fertig ###")                          # Appdaemon logging end position arrived
            if actualValue == minValue:                         # check if door is oben
                client.publish(domainTopic +"/" +stateTopic, "open")
                                                                # post open status of door for homeassistant
            if actualValue == maxValue:                         # check if door is closed
                client.publish(domainTopic +"/" +stateTopic, "close")
                                                                # post close status of door for homeassistant

This probably blocks the running thread. Try using the built-in MQTT API instead:


Thank you very much for the hint. I will look into this.

AppDaemon has built in MQTT support. Using it will help you get around this issue.

Alternately, for use cases where you need an always listening loop of some sort (like MQTT, or a websocket) AD version 4 supports async syntax which makes this possible to do without blocking. In AD version 3, embedding something like this into an app is not recommended as, like @tjntomas said, it will block the running thread and cause all kinds of issues.