def create_persistence_objects(server, max_update_interval, min_update_interval): env_var_db = server[ENVIRONMENTAL_DATA_POINT] module_db = server[FIRMWARE_MODULE] module_type_db = server[FIRMWARE_MODULE_TYPE] modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith("_") } modules = synthesize_firmware_module_info(modules, module_types) valid_vars = list(EnvVar.items.keys()) for module_id, module_info in modules.items(): for output_name, output_info in module_info["outputs"].items(): if not output_info["variable"] in valid_vars: rospy.logwarn( "Encountered a module output that references a " 'non-existant variable: Output "%s" of module "%s"', output_name, module_id) continue topic = "/sensors/{}/{}/filtered".format(module_id, output_name) topic_type = resolve_message_type(output_info["type"]) TopicPersistence(topic=topic, topic_type=topic_type, environment=module_info["environment"], variable=output_info["variable"], is_desired=False, db=env_var_db, max_update_interval=max_update_interval, min_update_interval=min_update_interval)
def filter_all_topics(module_db, module_type_db): modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith("_") } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for output_name, output_info in module_info["outputs"].items(): src_topic = "/sensors/{}/{}/raw".format(module_id, output_name) dest_topic = "/sensors/{}/{}/filtered".format( module_id, output_name) topic_type = get_message_class(output_info["type"]) filter_topic(src_topic, dest_topic, topic_type)
def connect_all_topics(module_db, module_type_db): modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith("_") } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for input_name, input_info in module_info["inputs"].items(): if not "actuators" in input_info["categories"]: continue src_topic = "/environments/{}/{}/commanded".format( module_info["environment"], input_info["variable"] ) dest_topic = "/actuators/{}/{}".format(module_id, input_name) dest_topic_type = get_message_class(input_info["type"]) src_topic_type = Float64 connect_topics( src_topic, dest_topic, src_topic_type, dest_topic_type, multiplier=input_info.get("multiplier", 1), deadband=input_info.get("deadband", 0) ) for output_name, output_info in module_info["outputs"].items(): if not "sensors" in output_info["categories"]: continue src_topic = "/sensors/{}/{}/raw".format(module_id, output_name) dest_topic = "/environments/{}/{}/raw".format( module_info["environment"], output_info["variable"] ) src_topic_type = get_message_class(output_info["type"]) dest_topic_type = Float64 connect_topics( src_topic, dest_topic, src_topic_type, dest_topic_type ) src_info_topic = "/sensors/{}/{}/info".format( module_id, output_name ) dest_info_topic = "/environments/{}/{}/info".format( module_info["environment"], output_info["variable"] ) connect_sensor_info_topics(src_info_topic, dest_info_topic)
def connect_all_topics(module_db, module_type_db): modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith("_") } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for input_name, input_info in module_info["inputs"].items(): if not "actuators" in input_info["categories"]: continue src_topic = "/environments/{}/{}/commanded".format( module_info["environment"], input_info["variable"]) dest_topic = "/actuators/{}/{}".format(module_id, input_name) dest_topic_type = get_message_class(input_info["type"]) src_topic_type = Float64 connect_topics(src_topic, dest_topic, src_topic_type, dest_topic_type, multiplier=input_info.get("multiplier", 1), deadband=input_info.get("deadband", 0)) for output_name, output_info in module_info["outputs"].items(): if not "sensors" in output_info["categories"]: continue src_topic = "/sensors/{}/{}/raw".format(module_id, output_name) dest_topic = "/environments/{}/{}/raw".format( module_info["environment"], output_info["variable"]) src_topic_type = get_message_class(output_info["type"]) dest_topic_type = Float64 connect_topics(src_topic, dest_topic, src_topic_type, dest_topic_type) src_info_topic = "/sensors/{}/{}/info".format( module_id, output_name) dest_info_topic = "/environments/{}/{}/info".format( module_info["environment"], output_info["variable"]) connect_sensor_info_topics(src_info_topic, dest_info_topic)
def connect_all_topics(module_db, module_type_db): modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith("_") } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for input_name, input_info in module_info["inputs"].items(): if not "actuators" in input_info["categories"]: continue src_topic = "/{}/{}".format(module_info["environment"], input_info["variable"]) dest_topic = "/actuators/{}/{}".format(module_id, input_name) dest_topic_type = resolve_message_type(input_info["type"]) src_topic_type = Float64 connect_topics(src_topic, dest_topic, src_topic_type, dest_topic_type, multiplier=input_info.get("direction", 1), threshold=input_info.get("threshold", 0)) for output_name, output_info in module_info["outputs"].items(): if not "sensors" in output_info["categories"]: continue src_topic = "/sensors/{}/{}/filtered".format( module_id, output_name) dest_topic = "/{}/measured/{}".format(module_info["environment"], output_info["variable"]) src_topic_type = resolve_message_type(output_info["type"]) dest_topic_type = Float64 connect_topics(src_topic, dest_topic, src_topic_type, dest_topic_type)
if __name__ == '__main__': rospy.init_node("sensor_info_publisher") # Connect to the DB server db_server = cli_config["local_server"]["url"] if not db_server: raise RuntimeError("No local server specified") server = Server(db_server) # Get info on all of the modules module_db = server[FIRMWARE_MODULE] module_type_db = server[FIRMWARE_MODULE_TYPE] modules = { module_id: FirmwareModule(module_db[module_id]) for module_id in module_db if not module_id.startswith('_') } module_types = { type_id: FirmwareModuleType(module_type_db[type_id]) for type_id in module_type_db if not type_id.startswith('_') } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for output_name, output_info in module_info["outputs"].items(): if not "sensors" in output_info["categories"]: continue publish_sensor_info(module_id, output_name, output_info) rospy.spin()
pub.publish(msg) if __name__ == '__main__': rospy.init_node("sensor_info_publisher") # Connect to the DB server db_server = cli_config["local_server"]["url"] if not db_server: raise RuntimeError("No local server specified") server = Server(db_server) # Get info on all of the modules firmware_module = rospy.get_param("/firmware_module") firmware_module_type = rospy.get_param("/firmware_module_type") modules = { record["_id"]: FirmwareModule(record) for record in firmware_module if not record["_id"].startswith('_') } module_types = { record["_id"]: FirmwareModuleType(record) for record in firmware_module_type if not record["_id"].startswith('_') } modules = synthesize_firmware_module_info(modules, module_types) for module_id, module_info in modules.items(): for output_name, output_info in module_info["outputs"].items(): if not "sensors" in output_info["categories"]: continue publish_sensor_info(module_id, output_name, output_info) rospy.spin()
def run(categories, modules_file, project_dir, plugin, target, status_update_interval): """ Generate code for this project and run it """ project_dir = os.path.abspath(project_dir) # Make sure the project has been initialized pio_config = os.path.join(project_dir, "platformio.ini") if not os.path.isfile(pio_config): raise click.ClickException( "Not an OpenAg firmware project. To initialize a new project " "please use the `openag firmware init` command") firmware_types = [] firmware = [] local_server = config["local_server"]["url"] server = Server(local_server) if local_server else None modules_json = json.load(modules_file) if modules_file else {} if modules_json.get(FIRMWARE_MODULE_TYPE): for module in modules_json[FIRMWARE_MODULE_TYPE]: click.echo( "Parsing firmware module type \"{}\" from modules file".format( module["_id"])) firmware_types.append(FirmwareModuleType(module)) elif server: db = server[FIRMWARE_MODULE_TYPE] for _id in db: if _id.startswith("_"): continue click.echo( "Parsing firmware module type \"{}\" from server".format(_id)) firmware_types.append(FirmwareModuleType(db[_id])) # Check for working modules in the lib folder # Do this second so project-local values overwrite values from the server lib_path = os.path.join(project_dir, "lib") for dir_name in os.listdir(lib_path): dir_path = os.path.join(lib_path, dir_name) if not os.path.isdir(dir_path): continue config_path = os.path.join(dir_path, "module.json") if os.path.isfile(config_path): with open(config_path) as f: click.echo("Parsing firmware module type \"{}\" from lib " "folder".format(dir_name)) doc = json.load(f) if not doc.get("_id"): # Patch in id if id isn't present doc["_id"] = parent_dirname(config_path) firmware_types.append(FirmwareModuleType(doc)) # Get the list of modules if modules_json.get(FIRMWARE_MODULE): for module in modules_json[FIRMWARE_MODULE]: click.echo( "Parsing firmware module \"{}\" from modules file".format( module["_id"])) firmware.append(FirmwareModule(module)) elif server: db = server[FIRMWARE_MODULE] for _id in db: if _id.startswith("_"): continue click.echo( "Parsing firmware module \"{}\" from server".format(_id)) firmware.append(FirmwareModule(db[_id])) if len(firmware) == 0: click.echo("Warning: no modules specified for the project") module_types = index_by_id(firmware_types) modules = index_by_id(firmware) # Synthesize the module and module type dicts modules = synthesize_firmware_module_info(modules, module_types) # Update the module inputs and outputs using the categories modules = prune_unspecified_categories(modules, categories) # Generate src.ino src_dir = os.path.join(project_dir, "src") src_file_path = os.path.join(src_dir, "src.ino") # Load the plugins plugin_fns = (load_plugin(plugin_name) for plugin_name in plugin) # Run modules through each plugin plugins = [plugin_fn(modules) for plugin_fn in plugin_fns] # Generate the code codegen = CodeGen(modules=modules, plugins=plugins, status_update_interval=status_update_interval) pio_ids = (dep["id"] for dep in codegen.all_pio_dependencies()) for _id in pio_ids: subprocess.call(["platformio", "lib", "install", str(_id)]) lib_dir = os.path.join(project_dir, "lib") for dep in codegen.all_git_dependencies(): url = dep["url"] branch = dep.get("branch", "master") dep_folder_name = make_dir_name_from_url(url) dep_folder = os.path.join(lib_dir, dep_folder_name) if os.path.isdir(dep_folder): click.echo('Updating "{}"'.format(dep_folder_name)) subprocess.call(["git", "checkout", "--quiet", branch], cwd=dep_folder) subprocess.call(["git", "pull"], cwd=dep_folder) else: click.echo('Downloading "{}"'.format(dep_folder_name)) subprocess.call(["git", "clone", "-b", branch, url, dep_folder], cwd=lib_dir) with open(src_file_path, "w+") as f: codegen.write_to(f) # Compile the generated code command = ["platformio", "run"] if target: command.append("-t") command.append(target) env = os.environ.copy() build_flags = [] for c in categories: build_flags.append("-DOPENAG_CATEGORY_{}".format(c.upper())) env["PLATFORMIO_BUILD_FLAGS"] = " ".join(build_flags) if subprocess.call(command, cwd=project_dir, env=env): raise click.ClickException("Compilation failed")
def _run( categories, param_file, project_dir, plugin, target, status_update_interval ): """ Generate code for this project and run it. Internal function we use for both run and flash commands. """ project_dir = os.path.abspath(project_dir) # Make sure the project has been initialized pio_config = os.path.join(project_dir, "platformio.ini") if not os.path.isfile(pio_config): raise click.ClickException( "Not an OpenAg firmware project. To initialize a new project " "please use the `openag firmware init` command" ) # @TODO in future we should pass in module config files as a thing # separate from the param file. name, ext = os.path.splitext(param_file.name) if ext == ".json": params = json.load(param_file) elif ext in (".yaml", ".yml"): params = yaml.load(param_file) else: raise ValueError("Param file must be YAML or JSON") firmware_type_params = params.get(FIRMWARE_MODULE_TYPE, []) firmware_params = params.get(FIRMWARE_MODULE, []) firmware_types = [ FirmwareModuleType(record) for record in firmware_type_params ] firmware = [ FirmwareModule(record) for record in firmware_params ] # Check for working modules in the lib folder # Do this second so project-local values overwrite values from the server lib_path = os.path.join(project_dir, "lib") for dir_name in os.listdir(lib_path): dir_path = os.path.join(lib_path, dir_name) if not os.path.isdir(dir_path): continue config_path = os.path.join(dir_path, "module.json") if os.path.isfile(config_path): with open(config_path) as f: click.echo( "Parsing firmware module type \"{}\" from lib " "folder".format(dir_name) ) doc = json.load(f) if not doc.get("_id"): # Patch in id if id isn't present doc["_id"] = parent_dirname(config_path) firmware_types.append(FirmwareModuleType(doc)) if len(firmware) == 0: click.echo("Warning: no modules specified for the project") module_types = index_by_id(firmware_types) modules = index_by_id(firmware) # Synthesize the module and module type dicts modules = synthesize_firmware_module_info(modules, module_types) # Update the module inputs and outputs using the categories modules = prune_unspecified_categories(modules, categories) # Generate src.ino src_dir = os.path.join(project_dir, "src") src_file_path = os.path.join(src_dir, "src.ino") # Load the plugins plugin_fns = (load_plugin(plugin_name) for plugin_name in plugin) # Run modules through each plugin plugins = [plugin_fn(modules) for plugin_fn in plugin_fns] # Generate the code codegen = CodeGen( modules=modules, plugins=plugins, status_update_interval=status_update_interval ) pio_ids = (dep["id"] for dep in codegen.all_pio_dependencies()) for _id in pio_ids: subprocess.call(["platformio", "lib", "install", str(_id)]) lib_dir = os.path.join(project_dir, "lib") for dep in codegen.all_git_dependencies(): url = dep["url"] branch = dep.get("branch", "master") dep_folder_name = make_dir_name_from_url(url) dep_folder = os.path.join(lib_dir, dep_folder_name) if os.path.isdir(dep_folder): click.echo('Updating "{}"'.format(dep_folder_name)) subprocess.call( ["git", "checkout", "--quiet", branch], cwd=dep_folder) subprocess.call(["git", "pull"], cwd=dep_folder) else: click.echo('Downloading "{}"'.format(dep_folder_name)) subprocess.call( ["git", "clone", "-b", branch, url, dep_folder], cwd=lib_dir) with open(src_file_path, "w+") as f: codegen.write_to(f) # Compile the generated code command = ["platformio", "run"] if target: command.append("-t") command.append(target) env = os.environ.copy() build_flags = [] for c in categories: build_flags.append("-DOPENAG_CATEGORY_{}".format(c.upper())) env["PLATFORMIO_BUILD_FLAGS"] = " ".join(build_flags) if subprocess.call(command, cwd=project_dir, env=env): raise click.ClickException("Compilation failed")