async def send_messages(self): """ Send messages in the queue to the sensor. """ await self._ready.wait() while not self.transport.is_closing(): instruction, args = await self.write_queue.get() if instruction == "ping": hm.send(self.transport, hm.make_ping()) elif instruction == "subscribe": uid, delay, params = args hm.send( self.transport, hm.make_subscription_request(hm.uid_to_device_id(uid), params, delay)) elif instruction == "read": uid, params = args hm.send(self.transport, hm.make_device_read(hm.uid_to_device_id(uid), params)) elif instruction == "write": uid, params_and_values = args hm.send( self.transport, hm.make_device_write(hm.uid_to_device_id(uid), params_and_values)) elif instruction == "disable": hm.send(self.transport, hm.make_disable()) elif instruction == "heartResp": uid = args[0] hm.send(self.transport, hm.make_heartbeat_response(self.read_queue.qsize()))
def device_write_thread(ser, instr_queue): """ Send packets to SER based on instructions from INSTR_QUEUE. """ try: while True: instruction, args = instr_queue.get() if instruction == "ping": hm.send(ser, hm.make_ping()) elif instruction == "subscribe": uid, delay, params = args hm.send( ser, hm.make_subscription_request(hm.uid_to_device_id(uid), params, delay)) elif instruction == "read": uid, params = args hm.send(ser, hm.make_device_read(hm.uid_to_device_id(uid), params)) elif instruction == "write": uid, params_and_values = args hm.send( ser, hm.make_device_write(hm.uid_to_device_id(uid), params_and_values)) elif instruction == "disable": hm.send(ser, hm.make_disable()) elif instruction == "heartResp": uid = args[0] hm.send(ser, hm.make_heartbeat_response()) except serial.SerialException: # Device has disconnected pass
async def recv_messages(self): """ Process received messages. """ await self._ready.wait() while not self.transport.is_closing(): if self.read_queue.qsize() >= PAUSE_QUEUE_SIZE: self.transport.pause_reading() if self.read_queue.qsize() <= RESUME_QUEUE_SIZE: self.transport.resume_reading() packet = await self.read_queue.get() message_type = packet.get_message_id() if message_type == hm.MESSAGE_TYPES["SubscriptionResponse"]: params, delay, uid = hm.parse_subscription_response(packet) self.uid = uid await self.state_queue.coro_put( ("device_subscribed", [uid, delay, params])) elif message_type == hm.MESSAGE_TYPES["DeviceData"]: # This is kind of a hack, but it allows us to use `recv_messages` for # detecting new smart sensors as well as reading from known ones. if self.uid is not None: params_and_values = hm.parse_device_data( packet, hm.uid_to_device_id(self.uid)) self.batched_data[uid] = params_and_values elif message_type == hm.MESSAGE_TYPES["HeartBeatRequest"]: if self.uid is not None: self.write_queue.put_nowait(("heartResp", [self.uid]))
def device_read_thread(uid, pack, error_queue, state_queue, batched_data): """ Read packets from SER and update queues and BATCHED_DATA accordingly. """ ser = pack.serial_port instruction_queue = pack.write_queue try: while True: for packet in hm.blocking_read_generator(ser): message_type = packet.get_message_id() if message_type == hm.MESSAGE_TYPES["SubscriptionResponse"]: params, delay, uid = hm.parse_subscription_response(packet) state_queue.put(("device_subscribed", [uid, delay, params])) elif message_type == hm.MESSAGE_TYPES["DeviceData"]: params_and_values = hm.parse_device_data( packet, hm.uid_to_device_id(uid)) batched_data[uid] = params_and_values elif message_type == hm.MESSAGE_TYPES["HeartBeatRequest"]: instruction_queue.put(("heartResp", [uid])) except serial.SerialException: error = namedtuple("Disconnect", ["uid", "instance_id", "accessed"]) error.uid = uid error.instance_id = pack.instance_id error.accessed = False error_queue.put(error)
def main_interface(): """ Render the main interface page. """ HIBIKE_INSTANCE.subscribe_all() from collections import namedtuple import time # Wait for Hibike to read from devices time.sleep(0.5) devices = [] for uid in HIBIKE_INSTANCE.uids: dev_id = hibike_message.uid_to_device_id(uid) dev_name = hibike_message.uid_to_device_name(uid) all_params = hibike_message.all_params_for_device_id(dev_id) params_list = [] for param_name in all_params: param = namedtuple( "Parameter", ("name", "type", "readable", "writeable", "init_value")) param.name = param_name param.type = hibike_message.param_type(dev_id, param_name) param.writeable = hibike_message.writable(dev_id, param_name) param.readable = hibike_message.readable(dev_id, param_name) param.init_value = HIBIKE_INSTANCE.get_last_cached(uid, param_name) params_list.append(param) params_list.sort(key=lambda p: p.name) device = namedtuple("Device", ("uid", "params", "name")) device.uid = uid device.params = params_list device.name = dev_name devices.append(device) return render_template("index.html", devices=devices)
def __init__(self, serial_port, params, delay, uid): self.serial_port = serial_port self.uid = uid self.device_type = hm.uid_to_device_id(uid) self.params = params self.delay = delay self.data = defaultdict(lambda: (None, -1))
def gen_random_sub_response(): """ Generate a random subscription response packet. """ uid = random_uid() device_id = hibike_message.uid_to_device_id(uid) params = random_params(device_id) delay = random.randrange(100) msg = hibike_message.make_subscription_response( device_id, params, delay, uid) return (ParsingTests.encode_packet(msg), )
def read_param(uid, param): """ Read a single device parameter. """ if uid not in HIBIKE_INSTANCE.uids: abort(404) params = hibike_message.all_params_for_device_id(hibike_message.uid_to_device_id(uid)) if param not in params: abort(404) return json.dumps({param: HIBIKE_INSTANCE.get_last_cached(uid, param)})
def device_write_thread(ser, queue): while True: instruction, args = queue.get() if instruction == "ping": hm.send(ser, hm.make_ping()) elif instruction == "subscribe": uid, delay, params = args hm.send( ser, hm.make_subscription_request(hm.uid_to_device_id(uid), params, delay)) elif instruction == "read": uid, params = args hm.send(ser, hm.make_device_read(hm.uid_to_device_id(uid), params)) elif instruction == "write": uid, params_and_values = args hm.send( ser, hm.make_device_write(hm.uid_to_device_id(uid), params_and_values))
def subscribe_all(self): """ Subscribe to all devices with all parameters. """ for uid in self.uids: dev_id = hibike_message.uid_to_device_id(uid) all_params = hibike_message.all_params_for_device_id(dev_id) readable_params = [] for param in all_params: if hibike_message.readable(dev_id, param): readable_params.append(param) self.pipe_to_child.send(["subscribe_device", [uid, self.DEFAULT_DELAY, readable_params]])
def _process_sub_request(self, msg): """Respond to a subscription request with an appropriate response.""" self.update_time = time.time() dev_id = hm.uid_to_device_id(self.uid) self.verbose_log("Subscription request received") params, delay = struct.unpack("<HH", msg.get_payload()) subscribed_params = hm.decode_params(dev_id, params) hm.send( self.transport, hm.make_subscription_response(dev_id, subscribed_params, delay, self.uid)) self.delay = delay self.subscribed_params.update(set(subscribed_params))
def read_all_params(uid): """ Read all parameters from a device. """ if uid not in HIBIKE_INSTANCE.uids: abort(404) dev_id = hibike_message.uid_to_device_id(uid) all_params = hibike_message.all_params_for_device_id(dev_id) readable_params = [p for p in all_params if hibike_message.readable(dev_id, p)] param_values = {} for param in readable_params: param_values[param] = HIBIKE_INSTANCE.get_last_cached(uid, param) return json.dumps(param_values)
def _process_device_read(self, msg): self.verbose_log("Device read received") device_id = hm.uid_to_device_id(self.uid) # Send a device data with the requested param and value tuples params, = struct.unpack("<H", msg.get_payload()) read_params = hm.decode_params(device_id, params) read_data = [] for param in read_params: if not (hm.readable(device_id, param) and param in self.param_values): raise ValueError( "Tried to read unreadable parameter {}".format(param)) read_data.append((param, self.param_values[param])) hm.send(self.transport, hm.make_device_data(device_id, read_data))
def device_read_thread(index, ser, instructionQueue, errorQueue, stateQueue): uid = None while True: packet = hm.blocking_read(ser) message_type = packet.getmessageID() if message_type == hm.messageTypes["SubscriptionResponse"]: params, delay, uid = hm.parse_subscription_response(packet) uid_to_index[uid] = index stateQueue.put(("device_subscribed", [uid, delay, params])) elif message_type == hm.messageTypes["DeviceData"]: if uid is not None: params_and_values = hm.parse_device_data( packet, hm.uid_to_device_id(uid)) stateQueue.put(("device_values", params_and_values)) else: print("[HIBIKE] Port %s received data before enumerating!!!" % ser.port)
def write_params(uid): """ Write values to a device. """ if uid not in HIBIKE_INSTANCE.uids: abort(404) all_params = set(hibike_message.all_params_for_device_id(hibike_message.uid_to_device_id(uid))) params = request.get_json(force=True, cache=False) if params is None: abort(400) params_and_values = [] for (param, value) in params.items(): if param not in all_params: abort(400) params_and_values.append((param, value)) HIBIKE_INSTANCE.write(uid, params_and_values) return "wrote value"
async def register_sensor(self, event_loop, devices, pending): """ Try to get our UID from the sensor and register it with `hibike_process`. """ await self._ready.wait() hm.send(self.transport, hm.make_ping()) await asyncio.sleep(IDENTIFY_TIMEOUT, loop=event_loop) if self.uid is None: self.quit() else: hm.send(self.transport, hm.make_ping()) hm.send( self.transport, hm.make_subscription_request(hm.uid_to_device_id(self.uid), [], 0)) devices[self.uid] = self pending.remove(self.transport.serial.name)
def get_device_info(uid): """ Get a dictionary representing information about a device. """ if uid not in HIBIKE_INSTANCE.uids: raise DeviceNotFoundError() device_id = hibike_message.uid_to_device_id(uid) device_name = hibike_message.device_id_to_name(device_id) params = hibike_message.all_params_for_device_id(device_id) json_map = {"device_name": device_name, "params": []} for param in params: readable = hibike_message.readable(device_id, param) writeable = hibike_message.writable(device_id, param) param_type = hibike_message.param_type(device_id, param) json_map["params"].append({"name": param, "readable": readable, "writeable": writeable, "type": param_type}) return json_map
async def send_subscribed_params(self): """Send values of subscribed parameters at a regular interval.""" await self._ready.wait() device_id = hm.uid_to_device_id(self.uid) while not self.transport.is_closing(): await asyncio.sleep(0.005, loop=self.event_loop) if self.update_time != 0 and self.delay != 0: if time.time() - self.update_time >= self.delay * 0.001: # If the time equal to the delay has elapsed since the previous device data, # send a device data with the device id # and the device's subscribed params and values data = [] for param in self.subscribed_params: data.append((param, self.param_values[param])) hm.send(self.transport, hm.make_device_data(device_id, data)) self.update_time = time.time() self.verbose_log("Regular data update sent from {}", hm.uid_to_device_name(self.uid))
def _process_device_write(self, msg): # Write to requested parameters # and return the values of the parameters written to using a device data self.verbose_log("Device write received") device_id = hm.uid_to_device_id(self.uid) write_params_and_values = hm.decode_device_write(msg, device_id) for (param, value) in write_params_and_values: if not (hm.writable(device_id, param) and param in self.param_values): raise ValueError( "Tried to write read-only parameter: {}".format(param)) self.param_values[param] = value updated_params = [] for (param, value) in write_params_and_values: if hm.readable(device_id, param): updated_params.append((param, value)) hm.send(self.transport, hm.make_device_data(device_id, updated_params))
newProcess = multiprocessing.Process( target=hibike_process, name="hibike_sim", args=[badThingsQueue, stateQueue, pipeFromChild]) newProcess.daemon = True newProcess.start() pipeToChild.send(["enumerate_all", []]) uids = set() while True: print("waiting for command") command, args = stateQueue.get() if command == "device_subscribed": uid = args[0] if uid not in uids: uids.add(uid) if hm.devices[hm.uid_to_device_id(uid)]["name"] == "TeamFlag": set_interval_sequence([ make_send_write(pipeToChild, uid, [("led1", 1), ("led2", 0), ("led3", 0), ("led4", 0), ("blue", 0), ("yellow", 0)]), make_send_write(pipeToChild, uid, [("led1", 0), ("led2", 1), ("led3", 0), ("led4", 0), ("blue", 0), ("yellow", 0)]), make_send_write(pipeToChild, uid, [("led1", 0), ("led2", 0),
def gen_random_device_id_and_params(): """ Generate a random device ID and set of parameters. """ device_id = hibike_message.uid_to_device_id(random_uid()) params = random_params(device_id) return (device_id, params)
def _process_ping(self, msg): """Respond to a ping packet.""" self.verbose_log("Ping received") dev_id = hm.uid_to_device_id(self.uid) hm.send(self.transport, hm.make_subscription_response(dev_id, [], 0, self.uid))
newProcess = multiprocessing.Process( target=hibike_process, name="hibike_sim", args=[main_error_queue, main_state_queue, from_child]) newProcess.daemon = True newProcess.start() to_child.send(["enumerate_all", []]) uids = set() while True: print("waiting for command") command, main_args = main_state_queue.get() if command == "device_subscribed": dev_uid = main_args[0] if dev_uid not in uids: uids.add(dev_uid) if hm.DEVICES[hm.uid_to_device_id( dev_uid)]["name"] == "YogiBear": set_interval_sequence([ make_send_write(to_child, dev_uid, [("duty_cycle", 0)]), make_send_write(to_child, dev_uid, [("duty_cycle", 0.5)]), make_send_write(to_child, dev_uid, [("duty_cycle", 1.0)]), make_send_write(to_child, dev_uid, [("duty_cycle", 0)]), make_send_write(to_child, dev_uid, [("duty_cycle", -0.5)]), make_send_write(to_child, dev_uid, [("duty_cycle", -1.0)]), make_send_write(to_child, dev_uid, [("duty_cycle", 0)]) ], 0.75)