Speech Parser script to extract entity Id information into readable form for Alexa or Google Assistant TTS

EDIT please note I have completely re-written the program and instructions following @ReneTode advice

EDIT1 Have updated script again. Warning options and syntax has changed again (sorry)

EDIT version 1.0 rewritten with regex to simplify the code also added new options. can now compare state values = >< + and -. See the code for new examples

EDIT: Version 1.1 correct parsing errors

EDIT: Version 2.0 now has a global search and replace . Translate option

EDIT Version 2.1 minor update

I have written a parameter driven Appdaemon script to extract multiple state attributes from multiple Entity Id’s and parse them into readable text ready to be sent to Alexa ( no reason why this won’t work for Google or any other TTS provider)

The script is triggered by a dummy bulb.

- platform: template
  lights:
    alexa_virtual:
      friendly_name: "Alexa Dummy Light"
      turn_on:

      turn_off:

      set_level:

This can be presented to Alexa (google ?) via HA Cloud, emulated hue, etc. The brightness levels (1-100) are then be used by my script to trigger the appropriate response

The bulb can be triggered by Alexa Routines or locally by motion sensors, time of day, NFC tags, etc.

The script requires the following parameters

SpeechParser:
  module: SpeechParser
  class: Speechparser
  trigger: "light.alexa_virtual"
  DEBUG: 1
  entities: 
    1: binary_sensor.door_window_sensor_158d00019e18bf #front door
    2: sensor.temperature_158d0001b9205b #living room temp
    3: group.gupstairs #  upstairs light
    4: binary_sensor.door_window_sensor_158d00019e1738 #  patio door
    5: weather.dark_sky #  weather forcast
  messages:
    1: "The {$01=FN} {$01=ST|on|is currently open}{$01=ST|off| is currently closed}"
    2: "The {$02=FN} is currently {$02=ST} centigrade"
    3: "The {$03=FN} are currently {$03=ST}"
    4: "The {$04=FN} {$04=ST|on|is currently open}{$04=ST|off|is currently closed}"
    5: "{g} on {d} the {D} of {m} {y} at {t}, The current outside temperture is {$05=TP} degrees, winspeed is {$05=wind_speed} miles per hour"
    6: "{$02>ST|10|danger, temperatures high}"
    7: "{$02>ST|$05=TP|Inside temperature is higher than the outside}"
    8: "{$02<ST|20|Inside temperature, is lower than 20 degress}"
  translate:
    1: morning|morgan

The messages in message list will be triggered if the brightness level of the dummy bulb matches the parameter number

Information inside {} is used to extract information from HA text outside of the brackets is unaltered.

The entities list is indexed from 1 to 99 and is used by the ${state} command to extract data.

Use the # to add comments to each entity to help identify objects.

The following commands can be used:

d = current day that can be spoken in words {31st}

D = current day in name {Monday}

m = current month in words {April}

y = current year {2018}

t = current time split so correctly spoken { 11 24 PM}

g = Greeting based on current time [morning: afternoon: evening]

The $ command has additional parameters that are order and position dependent

{$} State

$[00-99][=|>|<][attrib]|[test value|replace value [$[00-99]= attrib] [+] [-] [1] [2] ]

“$” state command
“00-99” number matches entities from apps.yaml
“=” show value to replace if value to test = value to replace
“>” show value to replace if value to test > value to replace
“<” show value if replace if value to test < value to replace
“attrib” state name in HA can be shortened see shortcuts in the code
“|” separator
“test value” alpha or if using < > must be numeric
“|” separator
“replace value” alpha or numeric. can be another state command
“[1]” will display test value.
“[2]” will display replace value
“[+]” sum the values
“[-]” will subtract always display a positive number

Examples

The {$01=friendly_name} is {$01=state} degrees

This will parse to "The living room temperature is 17 point 2 degrees"

This can be further shorted by using the following shortcuts

ST = state

FN = friendly_name

TP = temperature

BR = brightness

"The {$01=FN} is {$01=ST} degrees"

State values can be changed

“The {$01=FN} is {$01=ST|on|open}{$01=ST|off|closed}”

This will parse to "The Patio door is closed" {off being replaced by closed}

“{g} {D} the {d} of {m} {y} at {t} the current outside temperature is {$05=TP} degrees, winspeed is {$05=wind_speed} miles per hour”

This will parse to “Good morning on Thursday the Thirty first of October 2018 at 11 52 AM the current outside temperature is 3 point 2 degrees, wind speed is 1 point 4 miles per hour”

“{$05>ST|15|temperature too high}”

This will parse to “Temperature too high”; if temp is greater than 15" or if temp is <= 15

“{$05<ST|10|temperature too low}”

This will parse to “Temperature too low” if temp is less than 10 “” if temp is <= 10

{$02>ST|$05=TP|Inside temperature is higher than the outside}"

This will parse to Inside temperature is higher than the outside if $02 > (inside temp) $05 (outside temp)

“{$02>ST|$05=TP|Temperature is [1] degrees, [-] degrees higher than the outside temperature of [2] degrees}”

Temperature is 19.5 degrees, 5.5 degrees higher than the outside temperature of 10 degrees

There is limited error checking within the program. If any errors occur or the program does not work as expected. Set DEBUG: 1 . This will generate additional debug messages should highlight where the parsing errors occur.

I use the following for Alexa TTS

Simply change these highlighted lines in the script to redirect to your TTS device

    # Speech Parser
#
# Ver 1.0 
#
# Ver 1.1 Update Parse for removing dot from float numbers ensure did not replace full stops
#
# ver 1.2 remove : from final parse
#
# ver 2.0 added translate option
#
# ver 2.1 updated with ;atest vesion of alexa media player
#
# This program extracts information from entities  and converts them into a readable format
# for devices such as Alexa or google assistant to read.
# The program is triggered by a dummy bulb which can be then be presented to Alexa or Google.
# Depending on the brightness level { 1 to 100}  triggered this program will parse a command line
# to extract the required information. 

#SpeechParser:
#  module: SpeechParser
#  class: Speechparser
#  trigger: "light.alexa_virtual"
#  DEBUG: 1
#  entities:
#    1:binary_sensor.door_window_sensor_158d00019e18bf # front door sensor
#    2: sensor.temperature_158d0001b9205b # living room thermostat
#    3: group.gupstairs # upstairs lights
#    4: binary_sensor.door_window_sensor_158d00019e1738 # patio door sensor
#    5: weather.dark_sky # weather
#  messages:
#    1: "The {$01=FN} is {$01=ST|off|closed}{$01=ST|on|open}""
#    2: "The {$02=FN} is currently {$02=ST} centigrade"
#    3: "The {$03=FN} are currently {$03=ST}"
#    4: "The {$04=FN}{$04=ST|on|are open,please close now"}{$04=ST|off|closed}"
#    5: >
#        {g} on {d} the {D} of {m} {y} at {t} the current outside  temperature is {$05=TP}
#        degrees winspeed is {$05=wind_speed} miles per hour
#    6: "{$02>state|18|temperature too high}{$02<state|19|temperature too low}
#  translate:
#    1: morning|morgan
#
# Each parameter of the message list matches the brightness level of the dummy bulb so 1st  parameter is 1% and so on 
# Information inside {} is used to extract information from HA text outside of the brackets is unaltered.
# use yaml > to break down long message lines 
#
# The entities list is indexed from 1 to 99 and is used by the ${state} command to extract data. 
# Use the # to add comments to each entity to help identify objects.
# 
# The following commands can be used :
# 
# d = current day in spoken format {31st}
# D = current day in name {Monday}
# m = current month in words {April}
# y = current year  {2018}
# t = current time (12h) split so correctly spoken { 11 24 PM}
# g = Greeting based on current time [morning:afternoon:evening]
#
# The $ command has  additional parameters that are order dependent
# 
# {$} State
#
# $[00-99][=|>|<][attrib]|[test value|replace value [$[00-99]= attrib] [+] [-] [1] [2] ] 
#
# $                 state command
# 00-99             number matches entities from apps.yaml
# =                 show value to replace if value to test = value to replace
# >                 show value to replace if value to test > value to replace
# <                 show value if replace if value to test < value to replace
# attrib            state name in HA can be shorten see shortcuts in code
# |                 seperator  
# test value        alpha or if using < > must be numeric 
# |                 seperator
# replace value     alpha or numeric. can be another state command [1] will display
#                   test value. [2] will diplay replace value  [+] sum the values
#                   [-] will subtract always display positive number 
#
# The translate list (this is optional) is global search and replace . 
# It will replace any text in the final parse it has the following format
# 
# 1:source|replace
# 2:source|replace
# 
# any text before the | will be replaced with text after the | .  
#
# Examples 
#
#  "The {$01=friendly_name} is {$01=state} degrees"
# 
#   This will parse to "The living room temperature is 17 point 2 degrees" 
#
# This can be further shorted by using the following shortcuts
#
#   ST = state
#   FN = friendly_name
#   TP = temperature
#   BR = brightness
#
#   "The {$01=FN} is {$01=ST} degrees"
#
#   State values can be changed
#  
#  "The {$01=FN} is {$01=ST|on|open}{$01=ST|off|closed}
#
#  This will parse to  "The Patio door is closed"  {off being replaced by closed}
#  
#  "Good {g} {D} the {d} of  {m}  {y} at {t} the current outside  temperature is {$05=TP} degrees, winspeed is {$05=wind_speed} miles per hour"
#
#  This will parse to "Good morning on Thursday the Thirty first of October 2018 at 11 52 AM the current outside temperature is 3 point 2 degrees, wind speed is 1 point 4 miles per      # hour "
#
#  "{$05>ST|15|temperature too high}"
# 
#  This will parse to "Temperature too high" if temp is greater than 15 or "” if temp is <= 15
#
#  "{$05<ST|10|temperature too low, current temperature is [1] degrees }"
#
#  This will parse to "Temperature too low, current temperature is 6.5 degress"
#  if temp is less than 10  or "” if temp is >= 10
#
#  "{$02>ST|$05=TP|Temperature is [1] degrees, [-] degrees higher than the outside temperature of [2] degrees}"
#
#  Temperature is 19.5 degrees, 5.5 degrees higher than the outside temperature  of 10 degrees
#
#  There is limited error checking. So if there are any errors or the program does not work as expected.
#  Set DEBUG: 1 . This should hightlight where the parsing errors occur. Normally misplaced brackets 
#  or commands in the wrong order
#

import appdaemon.plugins.hass.hassapi as hass
class Speechparser(hass.Hass):
    
    def initialize(self):
        self.trigger=self.args["trigger"]
        self.listen_state(self.speechparser,self.trigger,new="on")
    def debug(self, text):
        if self.args["DEBUG"] == 1:
            self.log(text)
    def remove_dot(self, text):
        import re
        p = re.findall("(\d+.\d)", text)
        for i in p :
            t = i.replace("."," point ")
            text = text.replace(i,t)
        return text
    
    def speechparser (self, entity, attribute, old, new, kwargs):
        import subprocess
        import re
        self.log("{} triggered".format(self.trigger))
################################################################################
# change these lines for your TTS system.                                      #
# This uses last_called in the alexa media player via a template sensor        #                   #
# if only using 1 device change TTS_Voice = entity_id of alexa to respond      #
################################################################################
        self.call_service("alexa_media/update_last_called")                    #
        TTS_voice = self.get_state("sensor.last_alexa")                        #
################################################################################        
        self.debug("{} is the talking echo".format(TTS_voice))
# setup vars
        sub_cmd = {"d":"","D":"","m":"","y":"","t":"","g":""}
        num2words = {1:'1st',2:'2nd',3:'3rd',4:'4th',5:'5th',6:'6th',7:'7th',8:'8th',9:'9th',10:'10th',\
                     11:'11th',12:'12th',13:'13th',14:'14th',15:'15th',16:'16th',17:'17th',18:'18th',19:'19th',\
                     20:'20th',21:'21st',22:'22nd',23:'23rd',24:'24th',25:'25th',26:'26th',27:'27th',28:'28th',\
                     29:'29th',30:'30th',31:'31st'}
# load sub_cmd with current date time values
        now = self.datetime() 
        yr = now.strftime("%Y")
        cen,dec = divmod(int(yr),100)
        dayn = (now.strftime("%d"))
        sub_cmd["d"] = now.strftime("%A")
        sub_cmd["D"] = num2words[int(dayn)]
        sub_cmd["m"] = now.strftime("%B")
        mn = now.strftime("%M")
        hour = now.strftime("%I")
        am_pm = now.strftime("%p")
        sub_cmd["y"] = str(cen) + str(dec)
        sub_cmd["t"] = hour + " " + mn + " " + am_pm
        hr = int(hour)
        if am_pm == "AM" :
            greeting = "morning"
        if am_pm == "PM" and hr >= 5 :
            greeting = "evening"
        else :
            greeting = "afternoon"
        sub_cmd["g"] = greeting
        self.debug("{}".format(sub_cmd))
# get dummy light brightness
        v = self.get_state(self.trigger, attribute = "brightness")
# error checking
        if v == None :
            self.debug("Invalid trigger value {}".format(v))
            self.turn_off(self.trigger)
            return
# convert brightness 0-255 to %
        value = round((v/255*100))
        self.debug("Trigger value= {}".format(value))
# load params from apps.yaml
        try :
            ent = self.args["entities"]
        except:
            self.debug("No entities  options")
            ent  = ""
        try :
            mess = self.args["messages"]
        except:
            self.debug("No message options")
            return
        try :
            tran = self.args["translate"]
        except:
            self.debug("No translate options")
            tran = ""
        self.debug("{} of Entities {}".format(len(ent),ent))
        self.debug(" {} of Messages {}".format(len(mess),mess))
        self.debug(" {} of Translates {}".format(len(tran),tran))
        self.debug("Trigger value (%) {} bulb brightness {}".format(value,v))
# error checking
        if value > len(mess) or value == 0 or value > 99  :
            self.debug("Invalid trigger value {}".format(value))
            self.turn_off(self.trigger)
            return 
# get message line
        parse = mess[value]
# error checking
        if parse.count("{") != parse.count("}"):
            self.debug("Mismatch of {}")
            self.turn_off(self.trigger)
            return 
# error checking
        if parse.count("[") != parse.count("]"):
            self.debug("Mismatch of []")
            self.turn_off(self.trigger)
            return 
################################################################################
# shortcuts add as required                                                    #
################################################################################
        parse = parse.replace("FN","friendly_name").replace("TP","temperature")
        parse = parse.replace("BR","brightness").replace("ST","state")         
        
        self.debug("parse data = {}".format(parse))
# extract three types of message commands simple {.} short {......}
# and extended {......|*|*} via regex
        simple = re.findall("({[a-zA-Z]})",parse)
        short = re.findall("({.[0-9][0-9].\w+})",parse)
        extend = re.findall("({.[0-9=><\w]+\|.+?\|.+?})",parse)
        self.debug("simple {}".format(simple))
        self.debug("short {}".format(short))
        self.debug("extend {}".format(extend))
# loop to extract {.} commands
        for i in simple :
            scmd = i[1]
            sval = sub_cmd[scmd]
            parse = parse.replace(i,sval)
            self.debug("simple parse= {}".format(parse))
# loop to extract short commands {......}
        for i in short :
# regex to split command 
            scmd = re.findall("{(\$)([0-9][0-9])(.)(\w+)}",i)
            self.debug("scmd = {}".format(scmd))
            ind = int(scmd[0][1])
            st = scmd[0][3]
            self.debug("ind {} state {}".format(ind,st))
# get state value from HA
            sval = str((self.get_state(ent[ind], attribute = st)))
            sval = self.remove_dot(sval)
            parse = parse.replace(i,sval)
            self.debug("short parse= {}".format(parse))
# loop to extract extended commands {......|*|*}
        for i in extend :
# regex to split command 
            scmd = re.findall("{(\$)([0-9][0-9])(.)(\w+)\|(.+)\|(.+)}",i)
            self.debug("scmd = {}".format(scmd))
            ind = int(scmd[0][1])
            op = scmd[0][2]
            st = scmd[0][3]
            s1 = scmd[0][4]
            s2 = scmd[0][5]
            self.debug("ind {} state {}".format(ind,st))
# get state value from HA
            sval = str((self.get_state(ent[ind], attribute = st)))
# check if extended value is state 
            if s1[0] == "$" :
                ind= int(s1[1:3])
                st = s1[4:]
                self.debug("ind1 {} state {}".format(ind,st))
# get state value from HA
                cval =  str(self.get_state(ent[ind], attribute =st))
            else:
                cval = s1
# replace [] values
            s2 = s2.replace("[1]",sval)
            s2 = s2.replace("[2]",cval)
# stop TTS saying "dot"
            s2 = self.remove_dot(s2)
            self.debug("ext output parse= {}".format(s2))
# test operators
            self.debug("input value = {} replace Value = {}".format(s1,s2))
            self.debug("operator is {}".format(op))
            if op == "=" :
                if sval == cval :
                    sval = s2
                else :
                    sval = ""
            if op == "<"  or op == ">":
                posv =round(abs(float(sval) - float(cval)),2)
                posv = str(posv)
                val = s1 + s2
                val = str(val)
                s2 = s2.replace("[-]",posv)
                s2 = s2.replace("[+]",val)
                if float(sval) < float(cval) :
                    s2 = self.remove_dot(s2)
                    sval = s2
                elif float(sval) > float(cval) :
                    s2 = self.remove_dot(s2)
                    sval = s2
                else :
                    sval = ""
# update parse
            parse = parse.replace(i,sval)
            self.debug("extended parse= {}".format(parse))
################################################################################
# this is the parsed message ready for reading.remove white spaces and :       #
################################################################################        
        parse = " ".join(parse.split())
        parse = parse.replace(":","")
# add any translations
        for i in tran :
            self.debug("translate {}".format(tran[i]))
            scmd = re.findall("[a-zA-Z ,]*",tran[i])
            self.debug("translate source {} replace with  {}".format(scmd[0],scmd[2]))
            parse = parse.replace(scmd[0],scmd[2])
        self.debug("Message {} for {} is {}".format(value,TTS_voice,parse))   
################################################################################
# this is the code for sending messagae via alexa_media notify                 #
# replace with notify or whenever command used                                 #
################################################################################
        self.call_service("notify/alexa_media",data={"type":"tts"},message=parse,target=TTS_voice)
# turn off trigger bulb
        self.turn_off(self.trigger)
3 Likes

you did make a real project from it!
wow.

but your yaml is quite hard to read like this.
for certain because you also store entities.

you could think about using it this way:

  ent:
    - "The {{binary_sensor.door_window_sensor_158d00019e18bf.friendly_name}} is {{binary_sensor.door_window_sensor_158d00019e18bf.state(on=open,off=closed)}}"
    - "The {{sensor.temperature_158d0001b9205b.friendly_name}} is currently {{sensor.temperature_158d0001b9205b.state}} centigrade"
  • using {{ and }} makes it more like what is used in other languages
  • when you use sensor.temperature_158d0001b9205b.friendly_name or state, you dont need to store
  • the advantage you get is that you can easy add attributes in a structure like this
  • you can use ( and ) in the text (and for instance also use it to send a notify)
  • the yaml gets more readable

but its a nice project. i might borrow some of it :wink:

I have taken your advice and re-written the code.

now looks like this

“The {s0=FN} is {s0=ST|on|open|off|closed}”

The patio door is closed

and how do you know what entity s0 is?

New list of entities in the apps.yaml

SpeechParser:
  module: SpeechParser
  class: Speechparser
  trigger: "light.alexa_virtual"
  entities:
    - binary_sensor.door_window_sensor_158d00019e18bf
    - sensor.temperature_158d0001b9205b
    - group.gupstairs
    - binary_sensor.door_window_sensor_158d00019e1738
    - weather.dark_sky
  messages:
    - "The {s0=FN} is {s0=ST|on|open|off|closed}"
    - "The {s1=FN} is currently {s1=ST} centigrade"
    - "The {s2=FN} are currently {s2=ST}"
    - "The {s3=FN} is {s3=ST|on|open|off|closed}"
    - "{g} on {d} the {D} of {m} {y} at {t} the current outside  temperture is {s4=TP} degrees winspeed is
{s4=wind_speed} miles per hour"
    - " {s1>state|15|temperature too high}"

i would use friendly names instead of numbers, this will get confusing pretty quick.

  entities:
    backdoor: binary_sensor.door_window_sensor_158d00019e18bf
    temp_upstairs:  sensor.temperature_158d0001b9205b
    group_gupstairs: group.gupstairs
    living_window: binary_sensor.door_window_sensor_158d00019e1738
    weather: weather.dark_sky
  messages:
    - "The {backdoor=FN} is {backdoor=ST|on|open|off|closed}"
    - "The {temp_upstairs=FN} is currently {temp_upstairs=ST} centigrade"

i would also use more uniform seperators
{{ instead of {
. instead of =
(on:open,off:closed) instead of |on|open|off|closed

but i guess thats because i see that kind of stuff regularly since i started with HA. thats more like yaml, jinja, etc.
but its nothing more then a choice, and if you prefer those seperators then you should use those :wink:

but with the complete entities taken out of the text its better readably.
i like your total project.

i already taken a part from it.
i use limitlessled lights.
and to avoid restarting HA i already did at 12 lights with a temp name, without that they actually exist.
and i also had emulated hue autocreating the lights (was actually an overside from me)
so i got 12 dummy lights connected to Alexa

because of your idea i now use 1 of those to program.
first thing i implemented is an emergency call.
“alexa help”
now results in that alexa start announcing on all devices:
“attention attention attention, there is someone calling for help in {{lastalexa}}”
and ill probably also add flashing lights

The problem with friendly names is they are not unique. I need the entity id to find all the states quickly. A number of my devices have very similar names. living room lights, living room switch, living room temperature, so readability is still low. It also it extends the command lines in length

My parse works because the start of the command lines are fixed length. Makes the logic simpler, code quicker and helps my poor programming skills

I never use commas as a delimiter in input text lines as its too easy to get them embedded into lists giving you extra fields. By using split("|") I can guarantee my lists are clean. Remember the comma is the primary method of slowing Alexa speech down

On George 2 commands on ICL mainframes were separated by pipe symbols, so It’s an old bad habit but I do find the text more readable

i am not talking about friendly names you have set in HA, just look at my example. i mean readable names.
if you get away from fixed lengths you got way more flexibility.
just find the first {{ and the first }} and translate what is between.

your piping commands work, but for longer lists they get confusing.
on|open|off|closed|any|unknown|some|nothing
now you probably already need to start counting to see what replaces what.
but if you pair them up with anything, you dont need to count but see it immediatly
on|open;off|closed;any|unknown;some|nothing

and remember there is a big difference bewteen a comma in the text and a comma in the command.
you first find out what is between {{ and }} and a comma in there will be a seperator, a comma in the text wont be noticed.

so you get:

messageparts = message.split("{{")
for part in messageparts:
  if "}}" in part: #the first part probably is no command
    messageparts2 = part.split("}}")
    command = messageparts[0]
    # from this moment on nothing from the text is visible anymore, just command parts
    # at that moment i would split on (
    arglist = {}
    if "(" in command:
      commandparts = command.split("(")
      entitycommandpart = commandparts[0]
      stateargspart = commandparts[1][:-1]
      stateargs = stateargspart.split(",")
      for statearg in stateargs:
        x = statearg.split("|")
        arglist[x[0]] = x[1]
    else:
      entitycommandpart = command
   entitycommandparts = entitycommandpart.split["."]
   entity = entitycommandparts[0]
   commandtype = entitycommandparts[1]
   # now we have the command completely splitup to entity, commandtype and arglist
   # the real entity would be self.args["entities"][entity]
   # we can do an if for every commandtype (find friendly name or state or what else you would like
   # we use arglist to replace just by arglist[actual_state]

and this would work for

entities:
  door: binary_sensor.door_window_sensor_158d00019e18bf
  temp_upstairs:  sensor.temperature_158d0001b9205b
messages:
  - "i will tell you that {{door.FN}} is at this moment {{door.ST(on|open,off|closed)}}"
  - "i am happy to let you know that the temperature from {{temp_upstairs.FN}} is at the moment {{temp_upstairs.ST}} centigrade"

like this you can quickly add new functions you want to perform on the entity.
for instance recalculate brightness to 1 to 100 with command STBR or
replace texts in an input_select or anything you want to do, you just add an action and you can use readable names for the actions

as you see i just follow i real simple logic, because i am a real old style programmer :wink:
30 years ago i would do it the same in pascal :wink:

i hope that showing you how i would do it, will inspire you to make your code even better then it already is.

@ReneTode many thanks for time and interest in my scripts

I have re-written my scripts again. Steep learning curve, have discovered the joys of Regex.

I have looked and thought (pinched some of your code) about the syntax of the parser. I have streamlined and believe I have made the syntax smarter and more consistent. I’m still not using friendly names sorry :slight_smile:

I have removed on|open|off|closed and replaced with the following

I can now compare (= > < ) with text and numbers or two different states from two different entities to change the output

“{$02>ST|10|temperature is higher than 10 degrees}”

This parses to “temperature is higher than 10 degrees” if inside temp > 10 if <= 10 “” (blank)

“{$02>ST|$05=TP|Inside temperature is higher than the outside}”

This parses to “Inside Temperature is higher than the outside” if Inside temp > outside temp ( it had better be in November !) if not parses to “” (blank)

This makes very long messages using friendly names and increases parsing complexity

{insidetemp.>ST(outsidetemp.=TP|inside temperature is higher than the outside} (how can I determine if replacement is text or another entity ?)

I’m also looking at adding state information to the replaced text

"{$02>ST|$05=TP|The Inside temperature of {$02=ST} degrees is higher than the outside temperature of {$05=TP} degrees "

Also

"{$02>ST|$05=TP|The Inside temperature is [{$02=ST} - ($05=TP}] degrees higer than outside}

My entire state test is only 6 chars I agree its less readable but after dealing with Regex, it’s not that bad. It also massively shortens the message text.

The ability to compare state with state is very powerful and fixed length parsing make testing much simpler.

I’m still struggling with ensuring syntax is correct and the program doesn’t crash with bad messages. I have added a DEBUG flag in the parameters which has helped. Running last alexa adds 1.5 seconds to the runtime of the program. Any ideas ? to make quicker

never say sorry to me when you find something that you like!!!
after all its your project, and i am not even a user!!

all i want is to stear people into a general direction and work together, but the most important thing is that people are comfertable with their own project.

you advance with the things i offer, so you are better off with it, even when you dont take my approach.
and even if thats not the case, all i hope is that what i write makes you think what helps you advance.

and with the lot that i write probably 90% doesnt, but the 10% i write that helps you advance makes others advance. so thats all i want.

about making it faster? please share you code again tommorow (when i am not that much … sst i got a little to drink) and ill see what we can do to speed things up.

Have re-written code again. Now uses regex to break down messages much simpler code.

have added some new features

{$02>ST|$05=TP|Temperature is [1] degrees, [-] degrees higher than the outside temperature of [2] degrees}

will parse to if inside temp is greater than outside temp (entity 2 inside thermostat) ( entity 5 dark sky sensor)

Temperature is 19.5 degrees, 9.5 degrees higher than the outside temperature of 10 degrees

1 Like

Minor update

Complex example of what is possible with the speech parser

   10: >
       Good {g} here is  the latest report for {d} from home assistant , the inside temperature is 
       {$02=ST} degrees, outside temperature is {$05=TP} degrees, 
       current weather report  is as follows, {$16=ST},
       {$04=ST|on| Warning , The patio door is open}
       {$01=ST|on| Warning , The front door is open}
       The following lights are currently on,
       {$17=ST|on|Living room,}
       {$18=ST|on|Dining room,}
       {$19=ST|on|Kitchen,}
       {$20=ST|on|Utility,}
       {$21=ST|on|Front room,}
       {$22=ST|on|Landing,}
       {$23=ST|on|hall,}
       {$24=ST|on|Outside,}
       {$25=ST|on|Master bedroom, }
       {$26=ST|on|bathroom,}
       {$27=ST|on|bathroom fan,}
       {$28=ST|on|onsuite fan,}
       {$29=ST|on|onsuite,}
       {$30=ST|on|Madeline,}
       {$31=ST|on|Francis,}

This give the following output

Alexa Output

1 Like

I tried the dummy bulb example from above, seems like you have to change it to that.

because else I get an error:

  - platform: template
    lights:
      alexa_dummy:
        turn_on:
        turn_off:
        set_level:

mind lights is directly under platform.

Your right :slight_smile: . I have edited the post . Thank you

so my triggers looks like this, is there a better way to do this?

also i noticed when I set alexa up to turn on to 1% that is actually shows 2% in home assistant

  trigger:
    platform: state
    entity_id: light.alexa_dummy
    to: 'on'
  condition:
    - condition: template
      value_template: '{% if states.light.alexa_dummy.state %}{{ (states.light.alexa_dummy.attributes.brightness == 2) }}{% endif %}'

Or is this possible without a condition @petro

EDIT: about the 1% 2% thing. Turns out its not 2% its 1% of 255. How can I make the dummy light percentage too?

This looks like a great application. How are you getting data from Alexa? I use Alexa Home and all I can do it turn something on, off, or to a 0-100% brightness. Do you say something like, “Alexa set xlight to 10%” to trigger a response from bri=10?

It’s not percent, its a pot value. Hardware usually communicates via potentiometer values, which are usually 8 bit. 8 bit translates to numbers ranging from 0 to 255. It’s unit-less.

10% brightness in alexa is bri=26 in HA. I.E. 255* 0.1 rounded.

I use Alexa Routines .

So I Can say “Alexa have I left the doors open”.

  • The alexa routine sets the dummy bulb to 1%

  • The alexa app then say “Let me check that for you”

  • The Parser app triggers because the bulb has been set

  • The Parser app works our a sentence finding all the doors that are open

  • Use the last alexa features in the alexa media app to work out which alexa has spoken

  • Then sends the parsed sentence to the correct alexa to speak out

  • Turn off the bulb ready for the next trigger

Smoke and mirrors :slight_smile:"

1 Like

Ok, so I set it up to 1% and this shoudl give you 3 (poti value). rounded 2.55

But instead gives me 2.

Seems like the alexa app has shows rounded values. So maybe its not 1 but 1.5.

It’s possible that it doesn’t round and just truncates.

1 Like