def on_message(client, userdata, msg):
     try:
         self.log_debug("received mqtt message on " +
                        str(msg.topic))
         # find the sensor matching the topic
         for sensor_id in self.sensors:
             configuration = self.sensors[sensor_id]
             # exclude pull sensors
             if "topic" not in configuration:
                 continue
             # if the message is for this sensor
             if msg.topic == str(configuration["topic"]):
                 image = msg.payload
                 self.log_debug("received an image for " +
                                sensor_id)
                 # analyze the image
                 image = self.analyze_image(sensor_id,
                                            configuration, image)
                 if image is None:
                     return
                 image = base64.b64encode(image)
                 # prepare the message
                 message = Message(self)
                 message.recipient = "controller/hub"
                 message.command = "IN"
                 message.args = sensor_id
                 message.set("value", image)
                 # send the message to the controller
                 self.send(message)
                 break
     except Exception, e:
         self.log_error("Unable to process mqtt message: " +
                        exception.get(e))
 def on_start(self):
     # request all sensors' configuration so to filter sensors of interest
     self.add_configuration_listener("sensors/#", 1)
     # kill rtl_433 if running
     sdk.python.utils.command.run("killall rtl_433")
     # run rtl_433 and handle the output
     command = self.config['command']+" "+self.config['arguments']
     self.log_debug("running command "+command)
     process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     prev_output = ""
     while True:
         # read a line from the output
         output = process.stdout.readline()
         if output == '' and process.poll() is not None:
             # process ended, break
             self.log_info("rtl_433 has ended")
             break
         if output:
             # output available
             try:
                 # avoid handling the same exact output, skipping
                 if prev_output == output: continue
                 # parse the json output
                 json_output = json.loads(output)
             except Exception,e:
                 # not json format, ignoring
                 continue
             self.log_debug("Received: "+str(json_output))
             # for each registered sensor
             for sensor_id in self.sensors:
                 sensor = self.sensors[sensor_id]
                 # apply the filter if any
                 if "filter" in sensor:
                     search = {}
                     if "&" in sensor["filter"]: key_values = sensor["filter"].split("&")
                     else: key_values = [sensor["filter"]]
                     for key_value in key_values:
                         if "=" not in key_value: continue
                         key, value = key_value.split("=")
                         search[key] = value
                     # check if the output matches the search string
                     found = True
                     for key, value in search.iteritems():
                         # check every key/value pair
                         if key not in json_output: found = False
                         if str(value) != str(json_output[key]): found = False
                     if not found: continue
                 # prepare the message
                 message = Message(self)
                 message.recipient = "controller/hub"
                 message.command = "IN"
                 message.args = sensor_id
                 value = json_output[sensor["measure"]] if "measure" in sensor and sensor["measure"] in json_output else 1
                 message.set("value", value)
                 # send the measure to the controller
                 self.send(message)
                 self.log_debug("Matched sensor "+sensor_id+" with value "+str(value))
             # keep track of the last line of output
             prev_output = output
 def run_rule(self, rule_id, macro=None):
     # if macro is defined, run the rule for that macro only, otherwise run for all the macros
     macros = [macro] if macro is not None else self.rules[rule_id].keys()
     for macro in macros:
         rule = self.rules[rule_id][macro]
         # ensure this rule is not run too often to avoid loops
         if self.config[
                 "loop_safeguard"] > 0 and rule_id in self.last_run and macro in self.last_run[
                     rule_id] and time.time() - self.last_run[rule_id][
                         macro] < self.config["loop_safeguard"]:
             return
         # keep track of the last time this run has run
         if rule_id not in self.last_run: self.last_run[rule_id] = {}
         self.last_run[rule_id][macro] = time.time()
         self.log_debug("[" + rule_id + "][" + macro + "] running rule")
         # for each sensor we need the value which will be asked to the db module. Keep track of both values and requests
         if rule_id not in self.requests: self.requests[rule_id] = {}
         self.requests[rule_id][macro] = []
         if rule_id not in self.values: self.values[rule_id] = {}
         self.values[rule_id][macro] = {}
         # for every constant, store its value as is so will be ready for the evaluation
         if "constants" in rule:
             for constant_id, value in rule["constants"].iteritems():
                 self.values[rule_id][macro][constant_id] = value
         # for every variable, retrieve its latest value to the database
         if "variables" in rule:
             for variable_id, variable in rule["variables"].iteritems():
                 # process the variable string (0: request, 1: start, 2: end, 3: sensor_id)
                 match = re.match(self.variable_regexp, variable)
                 if match is None: continue
                 # query db for the data
                 command, start, end, sensor_id = match.groups()
                 message = Message(self)
                 message.recipient = "controller/db"
                 message.command = message.command = "GET_" + command if command != "" else "GET"
                 message.args = sensor_id
                 start = -1 if start is None else int(start)
                 end = -1 if end is None else int(end.replace(",", ""))
                 message.set("start", start)
                 message.set("end", end)
                 self.sessions.register(
                     message, {
                         "rule_id": rule_id,
                         "variable_id": variable_id,
                         "macro": macro,
                     })
                 self.log_debug("[" + rule_id + "][" + macro + "][" +
                                variable_id + "] requesting db for " +
                                message.command + " " + message.args +
                                ": " + str(message.get_data()))
                 self.send(message)
                 # keep track of the requests so that once all the data will be available the rule will be evaluated
                 self.requests[rule_id][macro].append(
                     message.get_request_id())
             # add a placeholder at the end to ensure the rule is not evaluated before all the definitions are retrieved
             self.requests[rule_id][macro].append("LAST")
         # if the rule requires no data to retrieve, just evaluate it
         if len(self.requests[rule_id][macro]) == 0:
             self.evaluate_rule(rule_id, macro)
 def on_message(client, userdata, msg):
     try:
         # find the sensor matching the topic
         for sensor_id in self.sensors:
             sensor = self.sensors[sensor_id]
             if mqtt.topic_matches_sub(sensor["topic"], msg.topic):
                 self.log_debug("received " + str(msg.payload) +
                                " for " + sensor_id + " on topic " +
                                str(msg.topic))
                 # if JSON payload is expected
                 if "key" in sensor:
                     try:
                         data = json.loads(msg.payload)
                         if sensor["key"] not in data:
                             return
                         # apply the filter if any
                         if "filter" in sensor:
                             search = {}
                             if "&" in sensor["filter"]:
                                 key_values = sensor["filter"].split(
                                     "&")
                             else:
                                 key_values = [sensor["filter"]]
                             for key_value in key_values:
                                 if "=" not in key_value: continue
                                 key, value = key_value.split("=")
                                 search[key] = value
                             # check if the output matches the search string
                             found = True
                             for key, value in search.iteritems():
                                 # check every key/value pair
                                 if key not in data: found = False
                                 if key in data and str(value).lower(
                                 ) != str(data[key]).lower():
                                     found = False
                             # not matching, skip to the next sensor
                             if not found: continue
                         value = data[sensor["key"]]
                     except Exception, e:
                         self.log_warning(
                             "Unable to parse JSON payload " +
                             str(msg.payload) + ": " + exception.get(e))
                         return
                 # else consider the entire payload
                 else:
                     value = msg.payload
                 # prepare the message
                 message = Message(self)
                 message.recipient = "controller/hub"
                 message.command = "IN"
                 message.args = sensor_id
                 message.set("value", value)
                 # send the measure to the controller
                 self.send(message)
     except Exception, e:
         self.log_warning("runtime error during on_message(): " +
                          exception.get(e))
         return
 def on_start(self):
     self.log_debug("listening for UDP datagrams on port " +
                    str(self.config["port_listen"]))
     # bind to the network
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
     sock.bind(("", self.config["port_listen"]))
     while True:
         try:
             # new data arrives
             data, addr = sock.recvfrom(1024)
             self.log_debug("received " + data)
             # the message is expected to be in JSON format
             data = json.loads(data)
             if data["type"] != "WirelessMessage": continue
             # parse content
             content = data["data"][0]
             # sensor just started
             if content == "STARTED":
                 self.log_info(data["id"] + " has just started")
                 self.tx(data["id"], "ACK", True)
             elif content == "AWAKE":
                 # send a message if there is something in the queue
                 if data["id"] in self.queue and len(
                         self.queue[data["id"]]) > 0:
                     self.tx(data["id"], queue[data["id"]])
                     self.queue[data["id"]] = []
             else:
                 # look for the sensor_id associated to this measure
                 sensor = None
                 for sensor_id in self.sensors:
                     if data["id"] == self.sensors[sensor_id][
                             "node_id"] and content.startswith(
                                 self.sensors[sensor_id]["measure"]):
                         sensor = self.sensors[sensor_id]
                         break
                 # if not registered, skip it
                 if sensor is None: continue
                 # prepare the message
                 message = Message(self)
                 message.recipient = "controller/hub"
                 message.command = "IN"
                 message.args = sensor_id
                 # generate the timestamp
                 # date_in = datetime.datetime.strptime(data["timestamp"],"%d %b %Y %H:%M:%S +0000")
                 # message.set("timestamp", int(time.mktime(date_in.timetuple())))
                 # strip out the measure from the value
                 message.set(
                     "value",
                     content.replace(self.sensors[sensor_id]["measure"],
                                     ""))
                 # send the measure to the controller
                 self.send(message)
         except Exception, e:
             self.log_warning("unable to parse " + str(data) + ": " +
                              exception.get(e))
 def event_callback(self, pin):
     if pin not in self.pins: return
     sensor_id = self.pins[pin]
     value = 1 if self.gpio_object.input(pin) else 0
     self.log_debug("GPIO input on pin " + str(pin) + " is now " +
                    str(value))
     message = Message(self)
     message.recipient = "controller/hub"
     message.command = "IN"
     message.args = sensor_id
     message.set("value", value)
     self.send(message)
 def process_message(self, update, context):
     # clean up request
     request = update.message.text.replace(
         "/" + self.config["command_handler"] + " ", "").lower()
     # ask our chatbot what to respond
     message = Message(self)
     message.recipient = "controller/chatbot"
     message.command = "ASK"
     message.set("request", request)
     message.set("accept", ["text", "image"])
     self.sessions.register(message, {"update": update})
     self.send(message)
示例#8
0
 def on_message(client, userdata, msg):
     # find the sensor matching the topic
     for sensor_id in self.sensors:
         sensor = self.sensors[sensor_id]
         if mqtt.topic_matches_sub(sensor["topic"], msg.topic):
             self.log_debug("received " + str(msg.payload) + " for " +
                            sensor_id + " on topic " + str(msg.topic))
             # prepare the message
             message = Message(self)
             message.recipient = "controller/hub"
             message.command = "IN"
             message.args = sensor_id
             message.set("value", msg.payload)
             # send the measure to the controller
             self.send(message)
 def on_start(self):
     while self.stopping == False:
         # init slack
         self.slack_init()
         if not self.slack_initialized:
             self.sleep(self.sleep_on_error)
             continue
         # connect to slack
         self.slack_connect()
         if not self.slack_connected:
             self.sleep(self.sleep_on_error)
             continue
         # read a rtm stream
         try:
             output_list = self.slack.rtm_read()
         except Exception, e:
             self.log_warning("unable to read from slack: " +
                              exception.get(e))
             self.slack_initialized = False
             self.slack_connected = False
             self.sleep(self.sleep_on_error)
             continue
         if output_list and len(output_list) > 0:
             for output in output_list:
                 if not output or 'text' not in output: continue
                 if output['user'] == self.bot_id: continue
                 # if the message is to the bot
                 if self.bot_id in output['text'] or self.config[
                         "bot_name"] in output['text'] or output[
                             'channel'].startswith("D"):
                     # clean up the request
                     request = output['text']
                     request = request.replace(self.config["bot_name"], '')
                     request = request.replace(self.bot_id, '')
                     request = request.lower()
                     channel = output['channel']
                     # ask our chatbot what to respond
                     message = Message(self)
                     message.recipient = "controller/chatbot"
                     message.command = "ASK"
                     message.set("request", request)
                     message.set("accept", ["text", "image"])
                     self.sessions.register(message, {"channel": channel})
                     self.send(message)
                     self.slack_typing(channel)
         self.sleep(1)
示例#10
0
 def on_message(client, userdata, msg):
     self.log_debug("received on "+str(msg.topic)+": "+str(msg.payload))
     # find the sensor matching the topic
     for sensor_id in self.sensors:
         configuration = self.sensors[sensor_id]
         # if the message is for this sensor
         if msg.topic.endswith("/"+str(configuration["device_id"])):
             # parse the payload
             try:
                 data = json.loads(msg.payload)
             except Exception,e:
                 self.log_warning("Unable to parse payload "+str(msg.payload)+": "+exception.get(e))
                 return
             # skip if key is missing from the payload
             if configuration["key"] not in data: 
                 continue
             # apply the filter if any
             if "filter" in configuration:
                 search = {}
                 if "&" in configuration["filter"]: key_values = configuration["filter"].split("&")
                 else: key_values = [configuration["filter"]]
                 for key_value in key_values:
                     if "=" not in key_value: continue
                     key, value = key_value.split("=")
                     search[key] = value
                 # check if the output matches the search string
                 found = True
                 for key, value in search.iteritems():
                     # check every key/value pair
                     if key not in data: found = False
                     if key in data and str(value).lower() != str(data[key]).lower(): found = False
                 # not matching, skip to the next sensor
                 if not found: continue
             value = data[configuration["key"]]
             # ignore empty values (when homeassistant is true, zigbee2mqtt will report an empty value just after a value
             if value == "": continue
             self.log_debug("reporting "+sensor_id+" with value "+str(value))
             # prepare the message
             message = Message(self)
             message.recipient = "controller/hub"
             message.command = "IN"
             message.args = sensor_id
             message.set("value", value)
             # send the measure to the controller
             self.send(message)
示例#11
0
 def on_start(self):
     # start the pulseaudio daemon
     self.log_info("Starting audio daemon...")
     self.log_debug(
         sdk.python.utils.command.run("setup/start_pulseaudio.sh"))
     # start the service
     input_file = "/tmp/audio_input.wav"
     listening_message = True
     while True:
         if listening_message:
             self.log_info("Listening for voice commands...")
         # run sox to record a voice sample trimming silence at the beginning and at the end
         device = "-t alsa " + str(
             self.config["device"]) if self.config["device"] != "" else ""
         command = "sox " + device + " " + input_file + " trim 0 " + str(
             self.recorder_max_duration) + " silence 1 " + str(
                 self.recorder_start_duration) + " " + str(
                     self.recorder_start_threshold) + "% 1 " + str(
                         self.recorder_end_duration) + " " + str(
                             self.recorder_end_threshold) + "%"
         sdk.python.utils.command.run(command)
         # ensure the sample contains any sound
         max_amplitude = sdk.python.utils.command.run(
             "killall sox 2>&1 2>/dev/null; sox " + input_file +
             " -n stat 2>&1|grep 'Maximum amplitude'|awk '{print $3}'")
         if not sdk.python.utils.numbers.is_number(max_amplitude) or float(
                 max_amplitude) == 0:
             listening_message = False
             continue
         self.log_info("Captured voice sample, processing...")
         listening_message = True
         # recognize the speech
         request = ""
         if self.config["engine"] == "google":
             # use the speech recognition engine to make google recognizing the file
             recognizer = speech_recognition.Recognizer()
             # open the input file
             with speech_recognition.AudioFile(input_file) as source:
                 audio = recognizer.record(source)
             try:
                 # perform the speech recognition
                 results = recognizer.recognize_google(
                     audio, show_all=True, language=self.house["language"])
                 # identify the best result
                 if len(results) != 0:
                     best_result = max(
                         results["alternative"],
                         key=lambda alternative: alternative["confidence"])
                     request = best_result["transcript"]
             except speech_recognition.UnknownValueError:
                 self.log_warning(
                     "Google Speech Recognition could not understand the audio"
                 )
             except speech_recognition.RequestError as e:
                 self.log_warning(
                     "Could not request results from Google Speech Recognition module; {0}"
                     .format(e))
         elif self.config["engine"] == "pocketsphinx":
             # run pocketsphinx to recognize the speech in the audio file
             language = self.house["language"].replace("-", "_")
             command = "pocketsphinx_continuous -infile " + input_file + " -hmm /usr/share/pocketsphinx/model/hmm/" + language + "/hub4wsj_sc_8k/ -dict /usr/share/pocketsphinx/model/lm/" + language + "/cmu07a.dic 2>/dev/null"
             output = sdk.python.utils.command.run(command)
             request = output.replace("000000000: ", "")
         if self.debug:
             # repeat the question
             message = Message(self)
             message.recipient = "notification/" + self.config["speaker"]
             message.command = "RUN"
             message.args = "info"
             message.set_data("I have understood: " + request)
             self.send(message)
         # ask the chatbot what to respond
         message = Message(self)
         message.recipient = "controller/chatbot"
         message.command = "ASK"
         message.set("request", request)
         message.set("accept", ["text"])
         self.send(message)
 def process_inbound(self, node_id, child_id, command, ack, type, payload):
     # ensure command and type are valid
     if command >= len(self.commands):
         self.log_error("[" + str(node_id) + "][" + str(child_id) +
                        "] command not supported: " + str(command))
         return
     if type >= len(self.types[command]):
         self.log_error("[" + str(node_id) + "][" + str(child_id) +
                        "] type not supported: " + str(type))
         return
     # map the correspoding command and type string
     command_string = self.commands[command]
     type_string = self.types[command][type]
     ack_string = self.acks[ack]
     self.log_debug("[" + str(node_id) + "][" + str(child_id) + "][" +
                    command_string + "][" + type_string + "][" +
                    ack_string + "] received: " + str(payload))
     # handle protocol messages
     if command_string == "PRESENTATION":
         # handle presentation messages
         self.log_debug("[" + str(node_id) + "][" + str(child_id) +
                        "] presented as " + type_string)
     elif command_string == "SET":
         # handle set messages (messages from sensors handled below)
         self.log_debug("[" + str(node_id) + "][" + str(child_id) + "][" +
                        command_string + "][" + type_string + "]: " +
                        payload)
     elif command_string == "REQ":
         # handle req messages
         self.log_debug("[" + str(node_id) + "][" + str(child_id) + "][" +
                        command_string + "][" + type_string + "]: " +
                        payload)
     elif command_string == "INTERNAL":
         # handle internal messages
         if type_string == "I_TIME":
             # return the time as requested by the sensor
             self.log_debug("[" + str(node_id) + "] requesting timestamp")
             self.tx(node_id, child_id, command_string, type_string,
                     int(time.time()))
         elif type_string == "I_SKETCH_NAME":
             # log the sketch name
             self.log_debug("[" + str(node_id) +
                            "] reported sketch name: " + str(payload))
         elif type_string == "I_SKETCH_VERSION":
             # log the sketch version
             self.log_debug("[" + str(node_id) +
                            "] reported sketch version: " + str(payload))
         elif type_string == "I_ID_REQUEST":
             # return the next available id
             self.log_debug("[" + str(node_id) + "] requesting node_id")
             # we assume low node_id are assigned statically and we can manage the upper end
             for id in range(100, 254):
                 found = False
                 # cycle over registered sensors
                 for sensor_id in self.sensors:
                     sensor = self.sensors[sensor_id]
                     if id == sensor["node_id"]:
                         found = True
                         break
                 # if id is already registered, go to the next
                 if found:
                     continue
                     # assign the id which is not allocated yet to the node
                 else:
                     self.tx(node_id, child_id, command_string,
                             "I_ID_RESPONSE", str(id))
                     break
         elif type_string == "I_CONFIG":
             # return the controller's configuration
             self.log_debug("[" + str(node_id) +
                            "] requesting configuration")
             metric = "I" if self.units == "imperial" else "M"
             self.tx(node_id, child_id, command_string, type_string, metric)
         elif type_string == "I_BATTERY_LEVEL":
             # log the battery level
             self.log_debug("[" + str(node_id) +
                            "] reporting battery level: " + str(payload) +
                            "%")
         elif type_string == "I_LOG_MESSAGE":
             # log a custom message
             self.log_debug("[" + str(node_id) + "] logging: " +
                            str(payload))
         elif type_string == "I_GATEWAY_READY":
             # report gateway report
             self.log_debug("[" + str(node_id) +
                            "] reporting gateway ready")
         elif type_string == "I_POST_SLEEP_NOTIFICATION":
             # report awake
             self.log_debug("[" + str(node_id) + "] reporting awake")
         elif type_string == "I_HEARTBEAT_RESPONSE" or type_string == "I_PRE_SLEEP_NOTIFICATION":
             # handle smart sleep
             self.log_debug("[" + str(node_id) + "] going to sleep")
             if node_id in self.queue and not self.queue[node_id].empty():
                 # process the queue
                 while not self.queue[node_id].empty():
                     node_id, child_id, command_string, type_string, payload = self.queue[
                         node_id].get()
                     # send the message
                     self.tx(node_id, child_id, command_string, type_string,
                             payload)
         else:
             self.log_debug("[" + str(node_id) + "] received " +
                            type_string)
     elif command_string == "STREAM":
         # handle stream messages
         return
     else:
         self.log_error(" Invalid command " + command_string)
     # handle messages for registered sensors
     for sensor_id in self.sensors:
         sensor = self.sensors[sensor_id]
         if node_id == sensor["node_id"] and child_id == sensor[
                 "child_id"] and command_string == sensor[
                     "command"] and type_string == sensor["type"]:
             # prepare the message
             message = Message(self)
             message.recipient = "controller/hub"
             message.command = "IN"
             message.args = sensor_id
             message.set("value", payload)
             # send the measure to the controller
             self.send(message)