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 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 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 _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))
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
def main(): """ Create virtual devices and send test data on them. """ parser = argparse.ArgumentParser() parser.add_argument('-d', '--device', required=True, help='device type') parser.add_argument('-p', '--port', required=True, help='serial port') parser.add_argument( '-v', '--verbose', help='print messages when sending and receiving packets', action="store_true") args = parser.parse_args() def verbose_log(fmt_string, *fmt_args): """ Log a message using a formatting string if verbosity is enabled. """ if args.verbose: print(fmt_string.format(*fmt_args)) device = args.device port = args.port verbose_log("Device {} on port {}", device, port) conn = serial.Serial(port, 115200) for device_num in hm.DEVICES: if hm.DEVICES[device_num]["name"] == device: device_id = device_num break else: raise RuntimeError("Invalid Device Name!!!") year = 1 randomness = random.randint(0, 0xFFFFFFFFFFFFFFFF) delay = 0 update_time = 0 uid = (device_id << 72) | (year << 64) | randomness # Here, the parameters and values to be sent in device datas # are set for each device type, the list of subscribed parameters is set to empty, if device == "LimitSwitch": subscribed_params = [] params_and_values = [("switch0", True), ("switch1", True), ("switch2", False), ("switch3", False)] if device == "ServoControl": subscribed_params = [] params_and_values = [("servo0", 2), ("enable0", True), ("servo1", 0), ("enable1", True), ("servo2", 5), ("enable2", True), ("servo3", 3), ("enable3", False)] if device == "Potentiometer": subscribed_params = [] params_and_values = [("pot0", 6.7), ("pot1", 5.5), ("pot2", 34.1), ("pot3", 0.15)] if device == "YogiBear": subscribed_params = [] params_and_values = [("enable", True), ("command_state", 1), ("duty_cycle", 1.0), ("pid_pos_setpoint", 2.0), ("pid_pos_kp", 3.0), ("pid_pos_ki", 4.0), ("pid_pos_kd", 5.0), ("pid_vel_setpoint", 6.0), ("pid_vel_kp", 7.0), ("pid_vel_ki", 8.0), ("pid_vel_kd", 9.0), ("current_thresh", 10.0), ("enc_pos", 11.0), ("enc_vel", 12.0), ("motor_current", 13.0), ("deadband", 0.5)] if device == "RFID": subscribed_params = [] params_and_values = [("id", 0), ("tag_detect", 0)] if device == "BatteryBuzzer": subscribed_params = [] params_and_values = [("is_unsafe", False), ("calibrated", True), ("v_cell1", 11.0), ("v_cell2", 11.0), ("v_cell3", 11.0), ("v_batt", 11.0), ("dv_cell2", 11.0), ("dv_cell3", 11.0)] if device == "LineFollower": subscribed_params = [] params_and_values = [("left", 1.0), ("center", 1.0), ("right", 1.0)] while True: if update_time != 0 and delay != 0: if time.time() - update_time >= 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 data_tuple in params_and_values: if data_tuple[0] in subscribed_params and hm.readable( device_id, data_tuple[0]): data.append(data_tuple) hm.send(conn, hm.make_device_data(device_id, data)) update_time = time.time() verbose_log("Regular data update sent from {}", device) msg = hm.read(conn) if not msg: time.sleep(.005) continue if msg.get_message_id() in [hm.MESSAGE_TYPES["SubscriptionRequest"]]: # Update the delay, subscription time, # and params, then send a subscription response verbose_log("Subscription request received") params, delay = struct.unpack("<HH", msg.get_payload()) subscribed_params = hm.decode_params(device_id, params) hm.send( conn, hm.make_subscription_response(device_id, subscribed_params, delay, uid)) update_time = time.time() if msg.get_message_id() in [hm.MESSAGE_TYPES["Ping"]]: # Send a subscription response verbose_log("Ping received") hm.send( conn, hm.make_subscription_response(device_id, subscribed_params, delay, uid)) if msg.get_message_id() in [hm.MESSAGE_TYPES["DeviceRead"]]: # Send a device data with the requested param and value tuples verbose_log("Device read received") params = struct.unpack("<H", msg.get_payload()) read_params = hm.decode_params(device_id, params) read_data = [] for data_tuple in params_and_values: if data_tuple[0] in read_params: if not hm.readable(device_id, data_tuple[0]): # Raise a syntax error if one of the values to be read is not readable raise SyntaxError( "Attempted to read an unreadable value") read_data.append(data_tuple) hm.send(conn, hm.make_device_data(device_id, read_data)) if msg.get_message_id() in [hm.MESSAGE_TYPES["DeviceWrite"]]: # Write to requested parameters # and return the values of the parameters written to using a device data verbose_log("Device write received") write_params_and_values = hm.decode_device_write(msg, device_id) write_params = [ param_val[0] for param_val in write_params_and_values ] value_types = [ hm.PARAM_MAP[device_id][name][1] for name in write_params ] write_tuples = [] # pylint: disable=consider-using-enumerate for index in range(len(write_params)): write_tuples.append( (write_params[index], write_params_and_values[index][1])) for new_tuple in write_tuples: if not hm.writable(device_id, new_tuple[0]): # Raise a syntax error if the value # that the message attempted to write to is not writable raise SyntaxError( "Attempted to write to an unwritable value") params_and_values[hm.PARAM_MAP[device_id][new_tuple[0]] [0]] = new_tuple # Send the written data, make sure you only send data for readable parameters index = 0 while index < len(write_params): if hm.readable(device_id, write_tuples[index][0]): index += 1 else: del write_tuples[index] hm.send(conn, hm.make_device_data(device_id, write_tuples))