Пример #1
0
def update(version, md5_server):
    """
    Execute the actual update: extract the archive and execute the bash update script.

    :param version: the new version (after the update).
    :param md5_server: the md5 sum provided by the server.
    """
    update_file = get_update_file()

    md5_client = md5(update_file)
    if md5_server != md5_client:
        raise Exception('MD5 of client (' + str(md5_client) +
                        ') and server (' + str(md5_server) + ') don\'t match')

    extract = subprocess.Popen('cd `dirname ' + update_file + '`; tar xzf ' +
                               update_file,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT,
                               shell=True)
    ret = extract.wait()
    extract_output = extract.stdout.read()

    if ret != 0:
        raise Exception('Extraction failed: ' + extract_output)

    update_script = subprocess.Popen(get_update_script() + ' `dirname ' +
                                     update_file + '`',
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT,
                                     shell=True)
    ret = update_script.wait()
    update_output = update_script.stdout.read()

    cleanup = subprocess.Popen('rm -Rf `dirname ' + update_file + '`/*',
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT,
                               shell=True)
    cleanup.wait()
    cleanup_output = update_script.stdout.read()

    if ret != 0:
        raise Exception('Error during update (ret=' + str(ret) + ') : ' +
                        update_output)
    else:
        config = ConfigParser()
        config.read(get_config_file())
        config.set('OpenMotics', 'version', version)
        with open(get_config_file(), 'wb') as configfile:
            config.write(configfile)

        return extract_output + '\n' + update_output + '\n' + cleanup_output
Пример #2
0
def main():
    """
    The main function runs a loop that waits for dbus calls, drives the leds and reads the
    switch.
    """
    try:
        config = ConfigParser()
        config.read(constants.get_config_file())

        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

        system_bus = dbus.SystemBus()
        _ = dbus.service.BusName("com.openmotics.status",
                                 system_bus)  # Initializes the bus
        # The above `_ = dbus...` need to be there, or the bus won't be initialized

        i2c_device = Hardware.get_i2c_device()
        i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

        status = StatusObject(system_bus, '/com/openmotics/status', i2c_device,
                              i2c_address, Hardware.get_gpio_input())
        status.start()

        status.set_led(Hardware.Led.POWER, True)

        LOGGER.log("Running led service.")
        mainloop = gobject.MainLoop()

        gobject.timeout_add(250, status.drive_leds)
        gobject.timeout_add(250, status.check_button)

        mainloop.run()
    except Exception as exception:
        LOGGER.log('Error starting led service: {0}'.format(exception))
Пример #3
0
    def __init__(self, configuration_controller=INJECTED):
        config = ConfigParser()
        config.read(constants.get_config_file())

        self._message_client = MessageClient('vpn_service')
        self._message_client.add_event_handler(self._event_receiver)
        self._message_client.set_state_handler(self._check_state)

        self._iterations = 0
        self._last_cycle = 0
        self._cloud_enabled = True
        self._sleep_time = 0
        self._previous_sleep_time = 0
        self._vpn_open = False
        self._debug_data = {}
        self._eeprom_events = deque()
        self._gateway = Gateway()
        self._vpn_controller = VpnController()
        self._config_controller = configuration_controller
        self._cloud = Cloud(config.get('OpenMotics', 'vpn_check_url') % config.get('OpenMotics', 'uuid'),
                            self._message_client,
                            self._config_controller)

        self._collectors = {'thermostats': DataCollector(self._gateway.get_thermostats, 60),
                            'inputs': DataCollector(self._gateway.get_inputs_status),
                            'outputs': DataCollector(self._gateway.get_enabled_outputs),
                            'pulses': DataCollector(self._gateway.get_pulse_counter_diff, 60),
                            'power': DataCollector(self._gateway.get_real_time_power),
                            'errors': DataCollector(self._gateway.get_errors, 600),
                            'local_ip': DataCollector(self._gateway.get_local_ip_address, 1800)}
Пример #4
0
    def __init__(self):
        config = ConfigParser()
        config.read(constants.get_config_file())

        self._iterations = 0
        self._last_cycle = 0
        self._cloud_enabled = True
        self._sleep_time = 0
        self._previous_sleep_time = 0
        self._vpn_open = False
        self._debug_data = {}
        self._eeprom_events = deque()
        self._gateway = Gateway()
        self._vpn_controller = VpnController()
        self._config_controller = ConfigurationController(constants.get_config_database_file(), threading.Lock())
        self._dbus_service = DBusService('vpn_service',
                                         event_receiver=self._event_receiver,
                                         get_state=self._check_state)
        self._cloud = Cloud(config.get('OpenMotics', 'vpn_check_url') % config.get('OpenMotics', 'uuid'),
                            self._dbus_service,
                            self._config_controller)

        self._collectors = {'thermostats': DataCollector(self._gateway.get_thermostats, 60),
                            'outputs': DataCollector(self._gateway.get_enabled_outputs),
                            'pulses': DataCollector(self._gateway.get_pulse_counter_diff, 60),
                            'power': DataCollector(self._gateway.get_real_time_power),
                            'errors': DataCollector(self._gateway.get_errors, 600),
                            'local_ip': DataCollector(self._gateway.get_local_ip_address, 1800)}
Пример #5
0
 def __init__(self, url=None):
     self._url = url
     if self._url is None:
         config = ConfigParser()
         config.read(constants.get_config_file())
         self._url = config.get('OpenMotics', 'vpn_check_url') % config.get(
             'OpenMotics', 'uuid')
Пример #6
0
def main():
    """ The main function runs a loop that waits for dbus calls, drives the leds and reads the
    switch. """
    config = ConfigParser()
    config.read(constants.get_config_file())

    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    system_bus = dbus.SystemBus()
    _ = dbus.service.BusName("com.openmotics.status",
                             system_bus)  # Initializes the bus.

    i2c_device = I2C_DEVICE_BBB if is_beagle_bone_black() else I2C_DEVICE_BB
    i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

    gpio_input = detect_button(GPIO_INPUT_BUTTON_GW_M, GPIO_INPUT_BUTTON_GW)

    status = StatusObject(system_bus, '/com/openmotics/status', i2c_device,
                          i2c_address, gpio_input)
    status.start()

    mainloop = gobject.MainLoop()
    gobject.timeout_add(100, status.network)
    gobject.timeout_add(100, status.serial)
    gobject.timeout_add(100, status.input)

    print "Running led service."
    mainloop.run()
Пример #7
0
def main():
    """
    The main function runs a loop that waits for dbus calls, drives the leds and reads the
    switch.
    """
    try:
        config = ConfigParser()
        config.read(constants.get_config_file())
        i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

        led_controller = LedController(Hardware.get_i2c_device(), i2c_address, Hardware.get_gpio_input())
        led_controller.start()
        led_controller.set_led(Hardware.Led.POWER, True)

        DBusService('led_service',
                    event_receiver=lambda *args, **kwargs: led_controller.event_receiver(*args, **kwargs),
                    get_state=led_controller.get_state)

        LOGGER.log("Running led service.")
        mainloop = gobject.MainLoop()
        gobject.timeout_add(250, led_controller.drive_leds)
        gobject.timeout_add(250, led_controller.check_button)
        mainloop.run()
    except Exception as exception:
        LOGGER.log('Error starting led service: {0}'.format(exception))
Пример #8
0
def setup_minimal_master_platform(port):
    # type: (str) -> None
    config = ConfigParser()
    config.read(constants.get_config_file())

    platform = Platform.get_platform()
    Injectable.value(controller_serial=Serial(port, 115200))

    if platform == Platform.Type.DUMMY:
        Injectable.value(maintenance_communicator=None)
        Injectable.value(master_controller=MasterDummyController())
    elif platform in Platform.CoreTypes:
        from master.core import ucan_communicator
        _ = ucan_communicator
        core_cli_serial_port = config.get('OpenMotics', 'cli_serial')
        Injectable.value(cli_serial=Serial(core_cli_serial_port, 115200))
        Injectable.value(master_communicator=CoreCommunicator())
        Injectable.value(maintenance_communicator=None)
        Injectable.value(memory_file=MemoryFile())
        Injectable.value(master_controller=MasterCoreController())
    elif platform in Platform.ClassicTypes:
        Injectable.value(
            eeprom_db=constants.get_eeprom_extension_database_file())
        from master.classic import eeprom_extension
        _ = eeprom_extension
        Injectable.value(master_communicator=MasterCommunicator())
        Injectable.value(maintenance_communicator=None)
        Injectable.value(master_controller=MasterClassicController())
    else:
        logger.warning('Unhandled master implementation for %s', platform)
Пример #9
0
def main():
    """
    The main function runs a loop that waits for om bus calls, drives the leds and reads the
    switch.
    """
    try:
        logger.info('Starting led service...')
        config = ConfigParser()
        config.read(constants.get_config_file())
        i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

        led_controller = LedController(Hardware.get_i2c_device(), i2c_address,
                                       Hardware.get_gpio_input())
        led_controller.start()
        led_controller.set_led(Hardware.Led.POWER, True)

        signal_request = {'stop': False}

        def stop(signum, frame):
            """ This function is called on SIGTERM. """
            _ = signum, frame
            logger.info('Stopping led service...')
            led_controller.stop()
            logger.info('Stopping led service...Done')
            signal_request['stop'] = True

        signal(SIGTERM, stop)
        logger.info('Starting led service... Done')
        while not signal_request['stop']:
            time.sleep(1)

    except Exception as exception:
        logger.exception('Error starting led service: {0}'.format(exception))
Пример #10
0
    def __init__(self, url=None, message_client=INJECTED):
        # type: (Optional[str], MessageClient) -> None
        config = ConfigParser()
        config.read(constants.get_config_file())

        self._message_client = message_client
        if self._message_client is not None:
            self._message_client.set_state_handler(self._check_state)

        self._last_successful_heartbeat = None  # type: Optional[float]
        self._last_cycle = 0.0
        self._cloud_enabled = True
        self._sleep_time = 0.0
        self._previous_sleep_time = 0.0
        self._gateway = Gateway()
        self._cloud = Cloud(url=url)
        self._task_executor = TaskExecutor()

        # Obsolete keys (do not use them, as they are still processed for legacy gateways):
        # `outputs`, `update`, `energy`, `pulse_totals`, `'thermostats`, `inputs`, `shutters`
        self._collectors = {
            'errors': DataCollector('errors', self._gateway.get_errors, 600),
            'local_ip': DataCollector('ip address', System.get_ip_address,
                                      1800)
        }
        self._debug_collector = DebugDumpDataCollector()
Пример #11
0
 def __init__(self, host="127.0.0.1"):
     self._host = host
     config = ConfigParser()
     config.read(constants.get_config_file())
     if config.has_option('OpenMotics', 'http_port'):
         self._port = config.get('OpenMotics', 'http_port')
     else:
         self._port = 80
Пример #12
0
def main():
    """ The main function. """
    parser = argparse.ArgumentParser(description='Tool to bootload a power module.')
    parser.add_argument('--address', dest='address', type=int,
                        help='the address of the power module to bootload')
    parser.add_argument('--all', dest='all', action='store_true',
                        help='bootload all power modules')
    parser.add_argument('--file', dest='file',
                        help='the filename of the hex file to bootload')
    parser.add_argument('--8', dest='old', action='store_true',
                        help='bootload for the 8-port power modules')
    parser.add_argument('--version', dest='version', action='store_true',
                        help='display the version of the power module(s)')
    parser.add_argument('--verbose', dest='verbose', action='store_true',
                        help='show the serial output')

    args = parser.parse_args()

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'power_serial')
    power_serial = RS485(Serial(port, 115200))
    power_communicator = PowerCommunicator(power_serial, None, time_keeper_period=0,
                                           verbose=args.verbose)
    power_communicator.start()

    if args.address or args.all:
        power_controller = PowerController(constants.get_power_database_file())
        power_modules = power_controller.get_power_modules()
        if args.all:
            for module_id in power_modules:
                module = power_modules[module_id]
                addr = module['address']
                if args.version:
                    print "E%d - Version: %s" % (addr, version(addr, power_communicator))
                if args.file:
                    if args.old and module['version'] == POWER_API_8_PORTS:
                        bootload_8(addr, args.file, power_communicator)
                    elif not args.old and module['version'] == POWER_API_12_PORTS:
                        bootload_12(addr, args.file, power_communicator)

        else:
            addr = args.address
            modules = [module for module in power_modules if module['address'] == addr]
            if len(modules) != 1:
                print 'ERROR: Could not determine energy module version. Aborting'
                sys.exit(1)
            if args.version:
                print "E%d - Version: %s" % (addr, version(addr, power_communicator))
            if args.file:
                if args.old and module['version'] == POWER_API_8_PORTS:
                    bootload_8(addr, args.file, power_communicator)
                elif not args.old and module['version'] == POWER_API_12_PORTS:
                    bootload_12(addr, args.file, power_communicator)

    else:
        parser.print_help()
Пример #13
0
    def get_platform():
        config = ConfigParser()
        config.read(constants.get_config_file())

        if config.has_option('OpenMotics', 'platform'):
            platform = config.get('OpenMotics', 'platform')
            if platform in Platform.Types:
                return platform
        return Platform.Type.CLASSIC
Пример #14
0
    def get_platform():
        # type: () -> str
        from six.moves.configparser import ConfigParser
        config = ConfigParser()
        config.read(constants.get_config_file())

        if config.has_option('OpenMotics', 'platform'):
            platform = config.get('OpenMotics', 'platform')
            if platform in Platform.Types:
                return platform
        return Platform.Type.CLASSIC
Пример #15
0
def update(version, md5_server):
    """
    Execute the actual update: extract the archive and execute the bash update script.

    :param version: the new version (after the update).
    :param md5_server: the md5 sum provided by the server.
    """
    update_file = get_update_file()

    md5_client = md5(update_file)
    if md5_server != md5_client:
        raise Exception('MD5 of client (' + str(md5_client) + ') and server (' + str(md5_server) + ') don\'t match')

    extract = subprocess.Popen('cd `dirname ' + update_file + '`; tar xzf ' + update_file,
                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    ret = extract.wait()
    extract_output = extract.stdout.read()

    if ret != 0:
        raise Exception('Extraction failed: ' + extract_output)

    update_script = subprocess.Popen(get_update_script() + ' `dirname ' + update_file + '`',
                                     stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    ret = update_script.wait()
    update_output = update_script.stdout.read()

    cleanup = subprocess.Popen('rm -Rf `dirname ' + update_file + '`/*',
                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    cleanup.wait()
    cleanup_output = update_script.stdout.read()

    if ret != 0:
        raise Exception('Error during update (ret=' + str(ret) + ') : ' + update_output)
    else:
        config = ConfigParser()
        config.read(get_config_file())
        config.set('OpenMotics', 'version', version)
        with open(get_config_file(), 'wb') as configfile:
            config.write(configfile)

        return extract_output + '\n' + update_output + '\n' + cleanup_output
Пример #16
0
 def https_port():
     # type: () -> int
     try:
         from six.moves.configparser import ConfigParser
         config = ConfigParser()
         config.read(constants.get_config_file())
         https_port = int(config.get('OpenMotics', 'https_port'))
         if https_port is None:
             https_port = 433  # default https port
         return https_port
     except Exception:
         return 433
Пример #17
0
def setup_minimal_power_platform():
    # type: () -> None
    config = ConfigParser()
    config.read(constants.get_config_file())
    power_serial_port = config.get('OpenMotics', 'power_serial')
    if power_serial_port:
        Injectable.value(power_db=constants.get_power_database_file())
        Injectable.value(power_store=PowerStore())
        Injectable.value(power_serial=RS485(
            Serial(power_serial_port, 115200, timeout=None)))
        Injectable.value(power_communicator=PowerCommunicator())
        Injectable.value(power_controller=PowerController())
        Injectable.value(p1_controller=P1Controller())
    else:
        Injectable.value(power_store=None)
        Injectable.value(power_communicator=None)
        Injectable.value(power_controller=None)
        Injectable.value(p1_controller=None)
        Injectable.value(power_serial=None)
Пример #18
0
    def __init__(self, path):
        # type: (str) -> None
        self._stopped = False
        self._path = path.rstrip('/')

        self._decorated_methods = {
            'input_status': [],
            'output_status': [],
            'shutter_status': [],
            'thermostat_status': [],
            'thermostat_group_status': [],
            'ventilation_status': [],
            'receive_events': [],
            'background_task': [],
            'on_remove': []
        }  # type: Dict[str,List[Any]]

        self._name = None
        self._version = None
        self._interfaces = []  # type: List[Any]
        self._exposes = []  # type: List[Any]
        self._metric_definitions = []  # type: List[Any]
        self._metric_collectors = []  # type: List[Any]
        self._metric_receivers = []  # type: List[Any]

        self._plugin = None
        self._writer = PluginIPCWriter(os.fdopen(sys.stdout.fileno(), 'wb', 0))
        self._reader = PluginIPCReader(os.fdopen(sys.stdin.fileno(), 'rb', 0),
                                       self._writer.log_exception)

        config = ConfigParser()
        config.read(constants.get_config_file())
        try:
            http_port = int(config.get('OpenMotics', 'http_port'))
        except (NoSectionError, NoOptionError):
            http_port = 80
        self._webinterface = WebInterfaceDispatcher(self._writer.log,
                                                    port=http_port)
Пример #19
0
def bootload_modules(type, filename, verbose, logger):
    """ Bootload all modules of the given type with the firmware in the given filename.

    :param type: Type of the modules (o, d, i, t, c)
    :type type: chr
    :param filename: The filename for the hex file to load
    :type filename: string
    :param verbose: If true the serial communication is printed.
    :param verbose: boolean
    """
    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'controller_serial')

    master_serial = Serial(port, 115200)
    master_communicator = MasterCommunicator(master_serial, verbose=verbose)
    master_communicator.start()

    addresses = get_module_addresses(master_communicator, type)

    blocks = 922 if type == 'c' else 410
    ihex = intelhex.IntelHex(filename)
    crc = calc_crc(ihex, blocks)

    success = True
    for address in addresses:
        logger("Bootloading module %s" % pretty_address(address))
        try:
            bootload(master_communicator, address, ihex, crc, blocks, logger)
        except Exception as exception:
            success = False
            logger("Bootloading failed")
            traceback.print_exc()

    return success
Пример #20
0
def main():
    """ The main function contains the loop that check if the vpn should be opened every 2 seconds.
    Status data is sent when the vpn is checked. """

    led_service = LedService()

    # Get the configuration
    config = ConfigParser()
    config.read(constants.get_config_file())

    check_url = config.get('OpenMotics', 'vpn_check_url') % config.get(
        'OpenMotics', 'uuid')

    gateway = Gateway()
    cloud = Cloud(check_url, led_service, ActionExecutor(gateway))

    collectors = {
        'energy':
        BufferingDataCollector(gateway.get_total_energy, 300),
        'thermostats':
        DataCollector(gateway.get_thermostats, 60),
        'pulse_totals':
        BufferingDataCollector(gateway.get_pulse_counter_status, 300),
        'pulses':
        DataCollector(gateway.get_pulse_counter_diff, 60),
        'outputs':
        DataCollector(gateway.get_enabled_outputs, mode='rt'),
        'power':
        DataCollector(gateway.get_real_time_power, mode='rt'),
        'update':
        DataCollector(gateway.get_update_status),
        'errors':
        DataCollector(gateway.get_errors, 600),
        'local_ip':
        DataCollector(gateway.get_local_ip_address, 1800),
        'modules':
        DataCollector(gateway.get_modules, mode='init'),
        'module_log':
        DataCollector(gateway.get_module_log, mode='init'),
        'last_inputs':
        DataCollector(gateway.get_last_inputs, mode='init'),
        'sensor_tmp':
        DataCollector(gateway.get_sensor_temperature_status, 10, mode='init'),
        'sensor_hum':
        DataCollector(gateway.get_sensor_humidity_status, 10, mode='init'),
        'sensor_bri':
        DataCollector(gateway.get_sensor_brightness_status, 10, mode='init')
    }

    iterations = 0

    # Loop: check vpn and open/close if needed
    while True:
        vpn_data = {}
        for collector_name in collectors:
            collector = collectors[collector_name]
            data = collector.collect(cloud.get_current_modes())
            if data is not None:
                vpn_data[collector_name] = data

        (success, should_open) = cloud.should_open_vpn(vpn_data)

        for collector_name in vpn_data.keys():
            collector = collectors[collector_name]
            if type(collector) == BufferingDataCollector:
                collector.data_sent_callback(success)

        if iterations > 20 and cloud.get_last_connect(
        ) < time.time() - REBOOT_TIMEOUT:
            # The cloud is not responding for a while, perhaps the BeagleBone network stack is
            # hanging, reboot the gateway to reset the BeagleBone.
            reboot_gateway()

        is_open = VpnController.check_vpn()
        led_service.set_led('vpn', is_open)

        if should_open and not is_open:
            print str(datetime.now()) + ": opening vpn"
            VpnController.start_vpn()
        elif not should_open and is_open:
            print str(datetime.now()) + ": closing vpn"
            VpnController.stop_vpn()

        print "Sleeping for %ds" % cloud.get_sleep_time()
        time.sleep(cloud.get_sleep_time())

        iterations += 1
Пример #21
0
def update(version, expected_md5):
    """
    Execute the actual update: extract the archive and execute the bash update script.

    :param version: the new version (after the update).
    :param expected_md5: the md5 sum provided by the server.
    """
    version_mapping = {}
    has_master_hardware = Platform.has_master_hardware()

    try:
        config = ConfigParser()
        config.read(constants.get_config_file())
        from_version = config.get('OpenMotics', 'version')
        logger.info('==================================')
        logger.info('Starting update {} -> {}'.format(from_version, version))

        update_file = constants.get_update_file()
        update_dir = os.path.dirname(update_file)
        # Change to update directory.
        os.chdir(update_dir)

        if os.path.exists(update_file):
            logger.info(' -> Extracting update.tgz')
            extract_legacy_update(update_file, expected_md5)
        else:
            logger.info(' -> Fetching metadata')
            meta = fetch_metadata(config, version, expected_md5)
            logger.info(' -> Downloading firmware for update {}'.format(meta['version']))
            for data in meta['firmwares']:
                download_firmware(data['type'], data['url'], data['sha256'])
                version_mapping[data['type']] = data['version']
    except Exception:
        logger.exception('failed to preprepare update')
        raise SystemExit(EXIT_CODES['failed_preprepare_update'])

    errors = []
    services_running = True
    try:
        date = datetime.now().strftime('%Y%m%d%H%M%S')

        # TODO: should update and re-execute itself before proceeding?

        logger.info(' -> Checking services')
        check_services()

        logger.info(' -> Stopping services')
        stop_services()
        services_running = False

        if has_master_hardware:
            gateway_os = FIRMWARE_FILES['gateway_os']
            if os.path.exists(gateway_os):
                os_version = version_mapping.get('gateway_os')
                logger.info(' -> Updating Gateway OS to {0}'.format(os_version if os_version else 'unknown version'))
                error = update_gateway_os(gateway_os, os_version)
                if error:
                    errors.append(error)

        gateway_service = FIRMWARE_FILES['gateway_service']
        if os.path.exists(gateway_service):
            service_version = version_mapping.get('gateway_service')
            logger.info(' -> Updating Gateway service to {0}'.format(service_version if service_version else 'unknown version'))
            error = update_gateway_backend(gateway_service, date, service_version)
            if error:
                errors.append(error)

        if has_master_hardware:
            master_type = get_master_type()
            master_firmware = FIRMWARE_FILES[master_type]
            if os.path.exists(master_firmware):
                master_version = version_mapping.get(master_type)
                logger.info(' -> Updating Master firmware to {0}'.format(master_version if master_version else 'unknown version'))
                error = update_master_firmware(master_type, master_firmware, master_version)
                if error:
                    errors.append(error)

            for module, filename, arguments in [('energy', FIRMWARE_FILES['energy'], []),
                                                ('power', FIRMWARE_FILES['power'], ['--8'])]:
                if os.path.exists(filename):
                    energy_version = version_mapping.get(module)
                    logger.info(' -> Updating {0} firmware to {1}'.format(module, energy_version if energy_version else 'unknown version'))
                    error = update_energy_firmware(module, filename, energy_version, arguments)
                    if error:
                        errors.append(error)

            for module in MODULE_TYPES:
                module_firmware = FIRMWARE_FILES[module]
                module_version = version_mapping.get(module)
                if os.path.exists(module_firmware):
                    logger.info(' -> Updating {0} firmware to {1}'.format(module, module_version if module_version else 'unknown version'))
                    error = update_module_firmware(module, module_firmware, module_version)
                    if error:
                        errors.append(error)

            logger.info('Checking master communication')
            check_master_communication()

        gateway_frontend = FIRMWARE_FILES['gateway_frontend']
        if os.path.exists(gateway_frontend):
            frontend_version = version_mapping.get('gateway_frontend')
            logger.info(' -> Updating Gateway frontend to {0}'.format(frontend_version if frontend_version else 'unknown version'))
            error = update_gateway_frontend(gateway_frontend, date, frontend_version)
            if error:
                errors.append(error)

        if os.path.exists(gateway_frontend) or os.path.exists(gateway_service):
            clean_update_backups()

        logger.info(' -> Starting services')
        start_services()
        services_running = True

        logger.info(' -> Waiting for health check')
        check_gateway_health()

    except Exception as exc:
        logger.exception('Unexpected exception updating')
        errors.append(exc)
        # TODO: rollback
    finally:
        if not services_running:
            logger.info(' -> Starting services')
            start_services()

        logger.info(' -> Running cleanup')
        cmd('rm -v -rf {}/*'.format(update_dir), shell=True)

        if errors:
            logger.error('Exceptions:')
            for error in errors:
                logger.error('- {0}'.format(error))
            raise errors[0]

        config.set('OpenMotics', 'version', version)
        temp_file = constants.get_config_file() + '.update'
        with open(temp_file, 'w') as configfile:
            config.write(configfile)
        shutil.move(temp_file, constants.get_config_file())
        cmd(['sync'])

        if os.path.exists('/tmp/post_update_reboot'):
            logger.info('Scheduling reboot in 5 minutes')
            subprocess.Popen('sleep 300 && reboot', close_fds=True, shell=True)

        logger.info('DONE')
        logger.info('exit 0')
Пример #22
0
def main():
    # type: () -> None
    """ The main function. """
    parser = argparse.ArgumentParser(description='Tool to control the master.')
    parser.add_argument('--port', dest='port', action='store_true',
                        help='get the serial port device')
    parser.add_argument('--sync', dest='sync', action='store_true',
                        help='sync the serial port')
    parser.add_argument('--reset', dest='reset', action='store_true',
                        help='reset the master')
    parser.add_argument('--hard-reset', dest='hardreset', action='store_true',
                        help='perform a hardware reset on the master')
    parser.add_argument('--version', dest='version', action='store_true',
                        help='get the version of the master')
    parser.add_argument('--wipe', dest='wipe', action='store_true',
                        help='wip the master eeprom')
    parser.add_argument('--update', dest='update', action='store_true',
                        help='update the master firmware')
    parser.add_argument('--master-firmware-classic',
                        help='path to the hexfile with the classic firmware')
    parser.add_argument('--master-firmware-core',
                        help='path to the hexfile with the core+ firmware')

    args = parser.parse_args()

    setup_logger()

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'controller_serial')
    if args.port:
        print(port)
        return

    if not any([args.sync, args.version, args.reset, args.hardreset, args.wipe, args.update]):
        parser.print_help()

    setup_minimal_master_platform(port)
    platform = Platform.get_platform()

    if args.hardreset:
        master_cold_reset()
        return
    elif args.update:
        if platform in Platform.CoreTypes:
            firmware = args.master_firmware_core
            if not firmware:
                print('error: --master-firmware-core is required to update')
                sys.exit(1)
        else:
            firmware = args.master_firmware_classic
            if not firmware:
                print('error: --master-firmware-classic is required to update')
                sys.exit(1)
        master_update(firmware)
        return

    communicator = get_communicator()
    communicator.start()
    try:
        if args.sync:
            master_sync()
        elif args.version:
            master_version()
        elif args.reset:
            master_reset()
        elif args.wipe:
            master_factory_reset()
    finally:
        communicator.stop()
Пример #23
0
def main():
    """
    The main function contains the loop that check if the vpn should be opened every 2 seconds.
    Status data is sent when the vpn is checked.
    """

    led_service = LedService()
    config_lock = threading.Lock()
    config_controller = ConfigurationController(constants.get_config_database_file(), config_lock)

    def set_vpn(_should_open):
        is_running = VpnController.check_vpn()
        if _should_open and not is_running:
            LOGGER.log(str(datetime.now()) + ": opening vpn")
            VpnController.start_vpn()
        elif not _should_open and is_running:
            LOGGER.log(str(datetime.now()) + ": closing vpn")
            VpnController.stop_vpn()
        is_running = VpnController.check_vpn()
        led_service.set_led(Hardware.Led.VPN, is_running and VpnController.vpn_connected())

    # Get the configuration
    config = ConfigParser()
    config.read(constants.get_config_file())
    check_url = config.get('OpenMotics', 'vpn_check_url') % config.get('OpenMotics', 'uuid')

    gateway = Gateway()
    cloud = Cloud(check_url, led_service, config_controller)

    collectors = {'thermostats': DataCollector(gateway.get_thermostats, 60),
                  'pulses': DataCollector(gateway.get_pulse_counter_diff, 60),
                  'outputs': DataCollector(gateway.get_enabled_outputs),
                  'power': DataCollector(gateway.get_real_time_power),
                  'update': DataCollector(gateway.get_update_status),
                  'errors': DataCollector(gateway.get_errors, 600),
                  'local_ip': DataCollector(gateway.get_local_ip_address, 1800)}

    iterations = 0

    previous_sleep_time = 0
    while True:
        try:
            # Check whether connection to the Cloud is enabled/disabled
            cloud_enabled = config_controller.get_setting('cloud_enabled')
            if cloud_enabled is False:
                set_vpn(False)
                led_service.set_led(Hardware.Led.CLOUD, False)
                led_service.set_led(Hardware.Led.VPN, False)
                time.sleep(30)
                continue

            vpn_data = {}

            # Collect data to be send to the Cloud
            for collector_name in collectors:
                collector = collectors[collector_name]
                data = collector.collect()
                if data is not None:
                    vpn_data[collector_name] = data

            # Send data to the cloud and see if the VPN should be opened
            should_open = cloud.should_open_vpn(vpn_data)

            if iterations > 20 and cloud.get_last_connect() < time.time() - REBOOT_TIMEOUT:
                # The cloud is not responding for a while.
                if not ping('cloud.openmotics.com') and not ping('8.8.8.8') and not ping(get_gateway()):
                    # Perhaps the BeagleBone network stack is hanging, reboot the gateway
                    # to reset the BeagleBone.
                    reboot_gateway()
            iterations += 1

            # Open or close the VPN
            set_vpn(should_open)

            # Getting some cleep
            sleep_time = cloud.get_sleep_time()
            if previous_sleep_time != sleep_time:
                LOGGER.log('Sleep time set to {0}s'.format(sleep_time))
                previous_sleep_time = sleep_time
            time.sleep(sleep_time)
        except Exception as ex:
            LOGGER.log("Error during vpn check loop: {0}".format(ex))
Пример #24
0
def main():
    supported_modules = ['O', 'R', 'D', 'I', 'T', 'C']
    supported_modules_gen3 = ['O3', 'R3', 'D3', 'I3', 'T3', 'C3']
    supported_can_modules = ['UC']
    all_supported_modules = supported_modules + supported_modules_gen3 + supported_can_modules

    parser = argparse.ArgumentParser(
        description='Tool to bootload the slave modules.')

    parser.add_argument(
        '-t',
        '--type',
        dest='type',
        choices=all_supported_modules +
        [m.lower() for m in all_supported_modules],
        required=True,
        help='The type of module to bootload (choices: {0})'.format(
            ', '.join(all_supported_modules)))
    parser.add_argument('-f',
                        '--file',
                        dest='file',
                        required=True,
                        help='The filename of the hex file to bootload')
    parser.add_argument('-v',
                        '--version',
                        dest='version',
                        required=False,
                        help='The version of the firmware to flash')
    parser.add_argument('--verbose',
                        dest='verbose',
                        action='store_true',
                        help='Show the serial output')

    args = parser.parse_args()
    module_type = args.type.upper()
    filename = args.file
    version = args.version
    gen3_firmware = module_type.endswith('3')
    if gen3_firmware:
        module_type = module_type[0]

    config = ConfigParser()
    config.read(constants.get_config_file())
    port = config.get('OpenMotics', 'controller_serial')

    setup_minimal_master_platform(port)

    communicator = get_communicator()
    communicator.start()
    try:
        if Platform.get_platform() in Platform.CoreTypes:
            from master.core.slave_updater import SlaveUpdater

            update_success = SlaveUpdater.update_all(
                module_type=module_type,
                hex_filename=filename,
                gen3_firmware=gen3_firmware,
                version=version)
        else:
            from master.classic.slave_updater import bootload_modules

            try:
                if os.path.getsize(args.file) <= 0:
                    print('Could not read hex or file is empty: {0}'.format(
                        args.file))
                    return False
            except OSError as ex:
                print('Could not open hex: {0}'.format(ex))
                return False

            if module_type == 'UC':
                print(
                    'Updating uCAN modules not supported on Classic platform')
                return True  # Don't fail the update

            update_success = bootload_modules(module_type=module_type,
                                              filename=filename,
                                              gen3_firmware=gen3_firmware,
                                              version=version)
    finally:
        communicator.stop()
        time.sleep(3)

    return update_success
Пример #25
0
def main():
    """ Main function. """
    log('Starting service...')

    config = ConfigParser()
    config.read(constants.get_config_file())

    defaults = {'username': config.get('OpenMotics', 'cloud_user'),
                'password': config.get('OpenMotics', 'cloud_pass')}
    controller_serial_port = config.get('OpenMotics', 'controller_serial')
    passthrough_serial_port = config.get('OpenMotics', 'passthrough_serial')
    power_serial_port = config.get('OpenMotics', 'power_serial')
    gateway_uuid = config.get('OpenMotics', 'uuid')

    config_lock = threading.Lock()
    user_controller = UserController(constants.get_config_database_file(), config_lock, defaults, 3600)
    config_controller = ConfigurationController(constants.get_config_database_file(), config_lock)

    dbus_service = DBusService('openmotics_service')

    controller_serial = Serial(controller_serial_port, 115200)
    power_serial = RS485(Serial(power_serial_port, 115200, timeout=None))

    master_communicator = MasterCommunicator(controller_serial)
    eeprom_controller = EepromController(
        EepromFile(master_communicator),
        EepromExtension(constants.get_eeprom_extension_database_file())
    )

    if passthrough_serial_port:
        passthrough_serial = Serial(passthrough_serial_port, 115200)
        passthrough_service = PassthroughService(master_communicator, passthrough_serial)
        passthrough_service.start()

    power_controller = PowerController(constants.get_power_database_file())
    power_communicator = PowerCommunicator(power_serial, power_controller)

    pulse_controller = PulseCounterController(
        constants.get_pulse_counter_database_file(),
        master_communicator,
        eeprom_controller
    )

    observer = Observer(master_communicator, dbus_service)
    gateway_api = GatewayApi(master_communicator, power_communicator, power_controller, eeprom_controller, pulse_controller, dbus_service, observer, config_controller)

    observer.set_gateway_api(gateway_api)

    scheduling_controller = SchedulingController(constants.get_scheduling_database_file(), config_lock, gateway_api)

    maintenance_service = MaintenanceService(gateway_api, constants.get_ssl_private_key_file(),
                                             constants.get_ssl_certificate_file())

    web_interface = WebInterface(user_controller, gateway_api, maintenance_service, dbus_service,
                                 config_controller, scheduling_controller)

    scheduling_controller.set_webinterface(web_interface)

    # Plugins
    plugin_controller = PluginController(web_interface, config_controller)
    web_interface.set_plugin_controller(plugin_controller)
    gateway_api.set_plugin_controller(plugin_controller)

    # Metrics
    metrics_cache_controller = MetricsCacheController(constants.get_metrics_database_file(), threading.Lock())
    metrics_collector = MetricsCollector(gateway_api, pulse_controller)
    metrics_controller = MetricsController(plugin_controller, metrics_collector, metrics_cache_controller, config_controller, gateway_uuid)
    metrics_collector.set_controllers(metrics_controller, plugin_controller)
    metrics_controller.add_receiver(metrics_controller.receiver)
    metrics_controller.add_receiver(web_interface.distribute_metric)

    plugin_controller.set_metrics_controller(metrics_controller)
    plugin_controller.set_metrics_collector(metrics_collector)
    web_interface.set_metrics_collector(metrics_collector)
    web_interface.set_metrics_controller(metrics_controller)

    web_service = WebService(web_interface, config_controller)
    plugin_controller.set_webservice(web_service)

    observer.subscribe_master(Observer.MasterEvents.INPUT_TRIGGER, metrics_collector.on_input)
    observer.subscribe_master(Observer.MasterEvents.INPUT_TRIGGER, plugin_controller.process_input_status)
    observer.subscribe_master(Observer.MasterEvents.ON_OUTPUTS, metrics_collector.on_output)
    observer.subscribe_master(Observer.MasterEvents.ON_OUTPUTS, plugin_controller.process_output_status)
    observer.subscribe_master(Observer.MasterEvents.ON_SHUTTER_UPDATE, plugin_controller.process_shutter_status)
    observer.subscribe_events(web_interface.process_observer_event)

    led_thread = threading.Thread(target=led_driver, args=(dbus_service, master_communicator, power_communicator))
    led_thread.setName("Serial led driver thread")
    led_thread.daemon = True
    led_thread.start()

    master_communicator.start()
    observer.start()
    power_communicator.start()
    metrics_controller.start()
    scheduling_controller.start()
    metrics_collector.start()
    web_service.start()
    gateway_api.start()
    plugin_controller.start()

    signal_request = {'stop': False}

    def stop(signum, frame):
        """ This function is called on SIGTERM. """
        _ = signum, frame
        log('Stopping service...')
        web_service.stop()
        metrics_collector.stop()
        metrics_controller.stop()
        plugin_controller.stop()
        log('Stopping service... Done')
        signal_request['stop'] = True

    signal(SIGTERM, stop)
    log('Starting service... Done')
    while not signal_request['stop']:
        time.sleep(1)
Пример #26
0
def setup_target_platform(target_platform, message_client_name):
    # type: (str, Optional[str]) -> None
    config = ConfigParser()
    config.read(constants.get_config_file())

    config_lock = Lock()
    metrics_lock = Lock()

    config_database_file = constants.get_config_database_file()

    # Debugging options
    try:
        debug_logger = config.get('OpenMotics', 'debug_logger')
        if debug_logger:
            logging.getLogger(debug_logger).setLevel(logging.DEBUG)
    except NoOptionError:
        pass

    # Webserver / Presentation layer
    try:
        https_port = int(config.get('OpenMotics', 'https_port'))
    except NoOptionError:
        https_port = 443
    try:
        http_port = int(config.get('OpenMotics', 'http_port'))
    except NoOptionError:
        http_port = 80
    Injectable.value(https_port=https_port)
    Injectable.value(http_port=http_port)
    Injectable.value(ssl_private_key=constants.get_ssl_private_key_file())
    Injectable.value(ssl_certificate=constants.get_ssl_certificate_file())

    # TODO: Clean up dependencies more to reduce complexity

    # IOC announcements
    # When below modules are imported, the classes are registerd in the IOC graph. This is required for
    # instances that are used in @Inject decorated functions below, and is also needed to specify
    # abstract implementations depending on e.g. the platform (classic vs core) or certain settings (classic
    # thermostats vs gateway thermostats)
    from plugins import base
    from gateway import (metrics_controller, webservice, scheduling, observer,
                         gateway_api, metrics_collector,
                         maintenance_controller, user_controller,
                         pulse_counter_controller, metrics_caching, watchdog,
                         output_controller, room_controller, sensor_controller,
                         shutter_controller, group_action_controller,
                         module_controller, ventilation_controller)
    from cloud import events
    _ = (metrics_controller, webservice, scheduling, observer, gateway_api,
         metrics_collector, maintenance_controller, base, events,
         user_controller, pulse_counter_controller, metrics_caching, watchdog,
         output_controller, room_controller, sensor_controller,
         shutter_controller, group_action_controller, module_controller,
         ventilation_controller)

    # IPC
    message_client = None
    if message_client_name is not None:
        message_client = MessageClient(message_client_name)
    Injectable.value(message_client=message_client)

    # Cloud API
    Injectable.value(gateway_uuid=config.get('OpenMotics', 'uuid'))

    try:
        parsed_url = urlparse(config.get('OpenMotics', 'vpn_check_url'))
    except NoOptionError:
        parsed_url = urlparse('')
    Injectable.value(cloud_endpoint=parsed_url.hostname)
    Injectable.value(cloud_port=parsed_url.port)
    Injectable.value(cloud_ssl=parsed_url.scheme == 'https')
    Injectable.value(cloud_api_version=0)

    cloud_url = urlunparse(
        (parsed_url.scheme, parsed_url.netloc, '', '', '', ''))
    Injectable.value(cloud_url=cloud_url or None)

    try:
        firmware_url = config.get('OpenMotics', 'firmware_url')
    except NoOptionError:
        path = '/portal/firmware_metadata'
        firmware_url = urlunparse(
            (parsed_url.scheme, parsed_url.netloc, path, '', '', ''))
    Injectable.value(firmware_url=firmware_url or None)

    # User Controller
    Injectable.value(user_db=config_database_file)
    Injectable.value(user_db_lock=config_lock)
    Injectable.value(token_timeout=3600)
    Injectable.value(
        config={
            'username': config.get('OpenMotics', 'cloud_user'),
            'password': config.get('OpenMotics', 'cloud_pass')
        })

    # Metrics Controller
    Injectable.value(metrics_db=constants.get_metrics_database_file())
    Injectable.value(metrics_db_lock=metrics_lock)

    # Energy Controller
    try:
        power_serial_port = config.get('OpenMotics', 'power_serial')
    except NoOptionError:
        power_serial_port = ''
    if power_serial_port:
        Injectable.value(power_db=constants.get_power_database_file())
        Injectable.value(power_store=PowerStore())
        # TODO: make non blocking?
        Injectable.value(power_serial=RS485(
            Serial(power_serial_port, 115200, timeout=None)))
        Injectable.value(power_communicator=PowerCommunicator())
        Injectable.value(power_controller=PowerController())
        Injectable.value(p1_controller=P1Controller())
    else:
        Injectable.value(power_serial=None)
        Injectable.value(power_store=None)
        Injectable.value(
            power_communicator=None)  # TODO: remove from gateway_api
        Injectable.value(power_controller=None)
        Injectable.value(p1_controller=None)

    # Pulse Controller
    Injectable.value(pulse_db=constants.get_pulse_counter_database_file())

    # Master Controller
    try:
        controller_serial_port = config.get('OpenMotics', 'controller_serial')
    except NoOptionError:
        controller_serial_port = ''

    if controller_serial_port:
        Injectable.value(controller_serial=Serial(
            controller_serial_port, 115200, exclusive=True))
    if target_platform in [Platform.Type.DUMMY, Platform.Type.ESAFE]:
        Injectable.value(maintenance_communicator=None)
        Injectable.value(passthrough_service=None)
        Injectable.value(master_controller=MasterDummyController())
        Injectable.value(eeprom_db=None)
        from gateway.hal.master_controller_dummy import DummyEepromObject
        Injectable.value(eeprom_extension=DummyEepromObject())
    elif target_platform in Platform.CoreTypes:
        # FIXME don't create singleton for optional controller?
        from master.core import ucan_communicator, slave_communicator
        _ = ucan_communicator, slave_communicator
        core_cli_serial_port = config.get('OpenMotics', 'cli_serial')
        Injectable.value(cli_serial=Serial(core_cli_serial_port, 115200))
        Injectable.value(passthrough_service=None)  # Mark as "not needed"
        # TODO: Remove; should not be needed for Core
        Injectable.value(
            eeprom_db=constants.get_eeprom_extension_database_file())

        Injectable.value(master_communicator=CoreCommunicator())
        Injectable.value(
            maintenance_communicator=MaintenanceCoreCommunicator())
        Injectable.value(memory_file=MemoryFile())
        Injectable.value(master_controller=MasterCoreController())
    elif target_platform in Platform.ClassicTypes:
        # FIXME don't create singleton for optional controller?
        from master.classic import eeprom_extension
        _ = eeprom_extension
        leds_i2c_address = config.get('OpenMotics', 'leds_i2c_address')
        passthrough_serial_port = config.get('OpenMotics',
                                             'passthrough_serial')
        Injectable.value(
            eeprom_db=constants.get_eeprom_extension_database_file())
        Injectable.value(leds_i2c_address=int(leds_i2c_address, 16))
        if passthrough_serial_port:
            Injectable.value(
                passthrough_serial=Serial(passthrough_serial_port, 115200))
            from master.classic.passthrough import PassthroughService
            _ = PassthroughService  # IOC announcement
        else:
            Injectable.value(passthrough_service=None)
        Injectable.value(master_communicator=MasterCommunicator())
        Injectable.value(
            maintenance_communicator=MaintenanceClassicCommunicator())
        Injectable.value(master_controller=MasterClassicController())
    else:
        logger.warning('Unhandled master implementation for %s',
                       target_platform)

    if target_platform in [Platform.Type.DUMMY, Platform.Type.ESAFE]:
        Injectable.value(frontpanel_controller=None)
    elif target_platform in Platform.CoreTypes:
        Injectable.value(frontpanel_controller=FrontpanelCoreController())
    elif target_platform in Platform.ClassicTypes:
        Injectable.value(frontpanel_controller=FrontpanelClassicController())
    else:
        logger.warning('Unhandled frontpanel implementation for %s',
                       target_platform)

    # Thermostats
    thermostats_gateway_feature = Feature.get_or_none(
        name='thermostats_gateway')
    thermostats_gateway_enabled = thermostats_gateway_feature is not None and thermostats_gateway_feature.enabled
    if target_platform not in Platform.ClassicTypes or thermostats_gateway_enabled:
        Injectable.value(thermostat_controller=ThermostatControllerGateway())
    else:
        Injectable.value(thermostat_controller=ThermostatControllerMaster())
Пример #27
0
def main():
    """ The main function. """
    parser = argparse.ArgumentParser(description='Tool to control the master.')
    parser.add_argument('--port', dest='port', action='store_true',
                        help='get the serial port device')
    parser.add_argument('--sync', dest='sync', action='store_true',
                        help='sync the serial port')
    parser.add_argument('--reset', dest='reset', action='store_true',
                        help='reset the master')
    parser.add_argument('--hard-reset', dest='hardreset', action='store_true',
                        help='perform a hardware reset on the master')
    parser.add_argument('--version', dest='version', action='store_true',
                        help='get the version of the master')
    parser.add_argument('--wipe', dest='wipe', action='store_true',
                        help='wip the master eeprom')

    args = parser.parse_args()

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'controller_serial')

    if args.port:
        print port

    elif args.hardreset:
        print 'Performing hard reset...'

        gpio_dir = open('/sys/class/gpio/gpio44/direction', 'w')
        gpio_dir.write('out')
        gpio_dir.close()

        def power(master_on):
            """ Set the power on the master. """
            gpio_file = open('/sys/class/gpio/gpio44/value', 'w')
            gpio_file.write('1' if master_on else '0')
            gpio_file.close()

        power(False)
        time.sleep(5)
        power(True)
        print 'Done performing hard reset'

    elif args.sync or args.version or args.reset or args.wipe:
        master_serial = Serial(port, 115200)
        master_communicator = MasterCommunicator(master_serial)
        master_communicator.start()

        if args.sync:
            print 'Sync...'
            try:
                master_communicator.do_command(master_api.status())
                print 'Done sync'
                sys.exit(0)
            except CommunicationTimedOutException:
                print 'Failed sync'
                sys.exit(1)

        elif args.version:
            status = master_communicator.do_command(master_api.status())
            print '{0}.{1}.{2} H{3}'.format(status['f1'], status['f2'], status['f3'], status['h'])

        elif args.reset:
            print 'Resetting...'
            try:
                master_communicator.do_command(master_api.reset())
                print 'Done resetting'
                sys.exit(0)
            except CommunicationTimedOutException:
                print 'Failed resetting'
                sys.exit(1)

        elif args.wipe:
            (num_banks, bank_size, write_size) = (256, 256, 10)
            print 'Wiping the master...'
            for bank in range(0, num_banks):
                print '-  Wiping bank {0}'.format(bank)
                for addr in range(0, bank_size, write_size):
                    master_communicator.do_command(
                        master_api.write_eeprom(),
                        {'bank': bank, 'address': addr, 'data': '\xff' * write_size}
                    )

            master_communicator.do_command(master_api.activate_eeprom(), {'eep': 0})
            print 'Done wiping the master'

    else:
        parser.print_help()
Пример #28
0
def main():
    """ The main function. """
    logger.info('Energy/Power Module bootloader')
    logger.info('Command: {0}'.format(' '.join(sys.argv)))

    parser = argparse.ArgumentParser(
        description='Tool to bootload a power module.')
    parser.add_argument('--address',
                        dest='address',
                        type=int,
                        help='the address of the power module to bootload')
    parser.add_argument('--all',
                        dest='all',
                        action='store_true',
                        help='bootload all power modules')
    parser.add_argument('--file',
                        dest='file',
                        help='the filename of the hex file to bootload')
    parser.add_argument('--8',
                        dest='old',
                        action='store_true',
                        help='bootload for the 8-port power modules')
    parser.add_argument('--verbose',
                        dest='verbose',
                        action='store_true',
                        help='show the serial output')

    args = parser.parse_args()

    if not args.file:
        parser.print_help()
        return

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'power_serial')
    power_serial = RS485(Serial(port, 115200))

    Injectable.value(power_serial=power_serial)
    Injectable.value(power_db=constants.get_power_database_file())

    power_controller = PowerController()
    power_communicator = PowerCommunicator(time_keeper_period=0,
                                           verbose=args.verbose)
    power_communicator.start()

    def _bootload(_module, _module_address, filename, is_power_module):
        try:
            if is_power_module and _module['version'] == POWER_API_8_PORTS:
                bootload_8(_module_address, filename, power_communicator)
            elif not is_power_module and _module[
                    'version'] == POWER_API_12_PORTS:
                bootload_12(_module_address, filename, power_communicator)
        except CommunicationTimedOutException:
            logger.warning(
                'E{0} - Module unavailable. Skipping...'.format(address))
        except Exception:
            logger.exception(
                'E{0} - Unexpected exception during bootload. Skipping...'.
                format(address))

    if args.address or args.all:
        power_modules = power_controller.get_power_modules()
        if args.all:
            for module_id in power_modules:
                module = power_modules[module_id]
                address = module['address']
                _bootload(module, address, args.file, is_power_module=args.old)
        else:
            address = args.address
            modules = [
                module for module in power_modules.values()
                if module['address'] == address
            ]
            if len(modules) != 1:
                logger.info(
                    'ERROR: Cannot find a module with address {0}'.format(
                        address))
                sys.exit(0)
            module = modules[0]
            _bootload(module, address, args.file, is_power_module=args.old)
    else:
        parser.print_help()
Пример #29
0
def main():
    """ Main function. """
    config = ConfigParser()
    config.read(constants.get_config_file())

    defaults = {
        'username': config.get('OpenMotics', 'cloud_user'),
        'password': config.get('OpenMotics', 'cloud_pass')
    }
    controller_serial_port = config.get('OpenMotics', 'controller_serial')
    passthrough_serial_port = config.get('OpenMotics', 'passthrough_serial')
    power_serial_port = config.get('OpenMotics', 'power_serial')
    gateway_uuid = config.get('OpenMotics', 'uuid')

    config_lock = threading.Lock()
    user_controller = UserController(constants.get_config_database_file(),
                                     config_lock, defaults, 3600)
    config_controller = ConfigurationController(
        constants.get_config_database_file(), config_lock)

    led_service = LedService()

    controller_serial = Serial(controller_serial_port, 115200)
    power_serial = RS485(Serial(power_serial_port, 115200, timeout=None))

    master_communicator = MasterCommunicator(controller_serial)

    if passthrough_serial_port:
        passthrough_serial = Serial(passthrough_serial_port, 115200)
        passthrough_service = PassthroughService(master_communicator,
                                                 passthrough_serial)
        passthrough_service.start()

    master_communicator.start(
    )  # A running master_communicator is required for the startup of services below

    power_controller = PowerController(constants.get_power_database_file())
    power_communicator = PowerCommunicator(power_serial, power_controller)

    gateway_api = GatewayApi(master_communicator, power_communicator,
                             power_controller)

    scheduling_controller = SchedulingController(
        constants.get_scheduling_database_file(), config_lock, gateway_api)

    maintenance_service = MaintenanceService(
        gateway_api, constants.get_ssl_private_key_file(),
        constants.get_ssl_certificate_file())

    web_interface = WebInterface(user_controller, gateway_api,
                                 maintenance_service,
                                 led_service.in_authorized_mode,
                                 config_controller, scheduling_controller)

    scheduling_controller.set_webinterface(web_interface)

    plugin_controller = PluginController(web_interface, config_controller)

    web_interface.set_plugin_controller(plugin_controller)
    gateway_api.set_plugin_controller(plugin_controller)

    # Metrics
    metrics_cache_controller = MetricsCacheController(
        constants.get_metrics_database_file(), threading.Lock())
    metrics_collector = MetricsCollector(gateway_api)
    metrics_controller = MetricsController(plugin_controller,
                                           metrics_collector,
                                           metrics_cache_controller,
                                           config_controller, gateway_uuid)
    metrics_collector.set_controllers(metrics_controller, plugin_controller)
    metrics_collector.set_plugin_intervals(plugin_controller.metric_intervals)
    metrics_controller.add_receiver(metrics_controller.receiver)
    metrics_controller.add_receiver(web_interface.distribute_metric)

    plugin_controller.set_metrics_controller(metrics_controller)
    web_interface.set_metrics_collector(metrics_collector)
    web_interface.set_metrics_controller(metrics_controller)

    web_service = WebService(web_interface, config_controller)

    def _on_output(*args, **kwargs):
        metrics_collector.on_output(*args, **kwargs)
        gateway_api.on_outputs(*args, **kwargs)

    def _on_input(*args, **kwargs):
        metrics_collector.on_input(*args, **kwargs)
        gateway_api.on_inputs(*args, **kwargs)

    master_communicator.register_consumer(
        BackgroundConsumer(master_api.output_list(), 0, _on_output, True))
    master_communicator.register_consumer(
        BackgroundConsumer(master_api.input_list(), 0, _on_input))

    power_communicator.start()
    plugin_controller.start_plugins()
    metrics_controller.start()
    scheduling_controller.start()
    metrics_collector.start()
    web_service.start()

    led_thread = threading.Thread(target=led_driver,
                                  args=(led_service, master_communicator,
                                        power_communicator))
    led_thread.setName("Serial led driver thread")
    led_thread.daemon = True
    led_thread.start()

    def stop(signum, frame):
        """ This function is called on SIGTERM. """
        _ = signum, frame
        sys.stderr.write("Shutting down")
        web_service.stop()
        metrics_collector.stop()
        metrics_controller.stop()
        plugin_controller.stop()

    signal(SIGTERM, stop)
Пример #30
0
def main():
    """ The main function. """
    parser = argparse.ArgumentParser(description='Tool to control the master.')
    parser.add_argument('--port',
                        dest='port',
                        action='store_true',
                        help='get the serial port device')
    parser.add_argument('--sync',
                        dest='sync',
                        action='store_true',
                        help='sync the serial port')
    parser.add_argument('--reset',
                        dest='reset',
                        action='store_true',
                        help='reset the master')
    parser.add_argument('--hard-reset',
                        dest='hardreset',
                        action='store_true',
                        help='perform a hardware reset on the master')
    parser.add_argument('--version',
                        dest='version',
                        action='store_true',
                        help='get the version of the master')
    parser.add_argument('--wipe',
                        dest='wipe',
                        action='store_true',
                        help='wip the master eeprom')

    args = parser.parse_args()

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'controller_serial')

    if args.port:
        print port
    elif args.hardreset:
        print "Performing hard reset"

        gpio_dir = open('/sys/class/gpio/gpio44/direction', 'w')
        gpio_dir.write('out')
        gpio_dir.close()

        def power(master_on):
            """ Set the power on the master. """
            gpio_file = open('/sys/class/gpio/gpio44/value', 'w')
            gpio_file.write('1' if master_on else '0')
            gpio_file.close()

        power(False)
        time.sleep(5)
        power(True)

        print "Done"
    elif args.sync or args.version or args.reset or args.wipe:
        master_serial = Serial(port, 115200)
        master_communicator = MasterCommunicator(master_serial)
        master_communicator.start()

        if args.sync:
            try:
                master_communicator.do_command(master_api.status())
            except CommunicationTimedOutException:
                print "Failed"
                sys.exit(1)
            else:
                print "Done"
                sys.exit(0)
        elif args.version:
            status = master_communicator.do_command(master_api.status())
            print "%d.%d.%d H%d" % (status['f1'], status['f2'], status['f3'],
                                    status['h'])
        elif args.reset:
            master_communicator.do_command(master_api.reset())
            print "Reset !"
        elif args.wipe:
            (num_banks, bank_size, write_size) = (256, 256, 10)
            print "Wiping the master"
            for bank in range(0, num_banks):
                print " Wiping bank %d" % bank
                for addr in range(0, bank_size, write_size):
                    master_communicator.do_command(master_api.write_eeprom(), {
                        'bank': bank,
                        'address': addr,
                        'data': '\xff' * write_size
                    })

            master_communicator.do_command(master_api.activate_eeprom(),
                                           {'eep': 0})
            print "Done wiping the master"

    else:
        parser.print_help()
Пример #31
0
 def get_main_version(self):
     """ Gets reported main version """
     _ = self
     config = ConfigParser()
     config.read(constants.get_config_file())
     return str(config.get('OpenMotics', 'version'))
Пример #32
0
def main():
    """ The main function. """
    logger.info('Bootloader for Energy/Power Modules and P1 Concentrator')
    logger.info('Command: {0}'.format(' '.join(sys.argv)))

    parser = argparse.ArgumentParser(description='Tool to bootload a module.')
    parser.add_argument('--address',
                        dest='address',
                        type=int,
                        help='the address of the module to bootload')
    parser.add_argument('--all',
                        dest='all',
                        action='store_true',
                        help='bootload all modules')
    parser.add_argument('--file',
                        dest='file',
                        help='the filename of the hex file to bootload')
    parser.add_argument('--8',
                        dest='old',
                        action='store_true',
                        help='bootload for the 8-port power modules')
    parser.add_argument('--p1c',
                        dest='p1c',
                        action='store_true',
                        help='bootload for the P1 concentrator modules')
    parser.add_argument('--verbose',
                        dest='verbose',
                        action='store_true',
                        help='show the serial output')
    parser.add_argument('--scan',
                        dest='scan',
                        action='store_true',
                        help='Scan the energy bus for modules')

    args = parser.parse_args()

    if not args.file and not args.scan:
        parser.print_help()
        return

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'power_serial')
    power_serial = RS485(Serial(port, 115200))

    Injectable.value(power_serial=power_serial)
    Injectable.value(power_db=constants.get_power_database_file())

    power_controller = PowerController()
    power_communicator = PowerCommunicator(time_keeper_period=0,
                                           verbose=args.verbose)
    power_communicator.start()

    if args.scan:
        logger.info('Scanning addresses 0-255...')
        for address in xrange(256):
            for module_type, version in {
                    'E/P': power_api.ENERGY_MODULE,
                    'C': power_api.P1_CONCENTRATOR
            }.iteritems():
                try:
                    logger.info('{0}{1} - Version: {2}'.format(
                        module_type, address,
                        get_module_firmware_version(address, version,
                                                    power_communicator)))
                except Exception:
                    pass
        logger.info('Scan completed')
        return

    version = power_api.ENERGY_MODULE
    if args.old:
        version = power_api.POWER_MODULE
    elif args.p1c:
        version = power_api.P1_CONCENTRATOR

    def _bootload(_module, _module_address, filename):
        try:
            if version == _module['version'] == power_api.POWER_MODULE:
                bootload_power_module(_module_address, filename,
                                      power_communicator)
            elif version == _module['version'] == power_api.ENERGY_MODULE:
                bootload_energy_module(_module_address, filename,
                                       power_communicator)
            elif version == _module['version'] == power_api.P1_CONCENTRATOR:
                bootload_p1_concentrator(_module_address, filename,
                                         power_communicator)
        except CommunicationTimedOutException:
            logger.warning(
                'E{0} - Module unavailable. Skipping...'.format(address))
        except Exception:
            logger.exception(
                'E{0} - Unexpected exception during bootload. Skipping...'.
                format(address))

    if args.address or args.all:
        power_modules = power_controller.get_power_modules()
        if args.all:
            for module_id in power_modules:
                module = power_modules[module_id]
                address = module['address']
                _bootload(module, address, args.file)
        else:
            address = args.address
            modules = [
                module for module in power_modules.values()
                if module['address'] == address
            ]
            if len(modules) != 1:
                logger.info(
                    'ERROR: Cannot find a module with address {0}'.format(
                        address))
                sys.exit(0)
            module = modules[0]
            _bootload(module, address, args.file)
    else:
        parser.print_help()
Пример #33
0
def main():
    """ The main function. """
    parser = argparse.ArgumentParser(
        description=
        'Tool to bootload the slave modules (output, dimmer, input and temperature).'
    )

    parser.add_argument(
        '-t',
        '--type',
        dest='type',
        choices=['o', 'r', 'd', 'i', 't', 'c', 'O', 'R', 'D', 'I', 'T', 'C'],
        required=True,
        help='the type of module to bootload (choices: O, R, D, I, T, C)')
    parser.add_argument('-f',
                        '--file',
                        dest='file',
                        required=True,
                        help='the filename of the hex file to bootload')
    parser.add_argument('-l', '--log', dest='log', required=False)
    parser.add_argument('-V',
                        '--verbose',
                        dest='verbose',
                        action='store_true',
                        help='show the serial output')

    args = parser.parse_args()

    config = ConfigParser()
    config.read(constants.get_config_file())

    port = config.get('OpenMotics', 'controller_serial')

    master_serial = Serial(port, 115200)
    Injectable.value(controller_serial=master_serial)

    log_file = None
    try:
        if args.log is not None:
            try:
                log_file = open(args.log, 'a')
            except IOError as ex:
                print 'Could not open the requested log file: {0}'.format(ex)
                return False
            logger = lambda msg: log_file.write('{0}\n'.format(msg))
        else:
            logger = lambda msg: sys.stdout.write('{0}\n'.format(msg))
        try:
            if os.path.getsize(args.file) <= 0:
                print 'Could not read hex or file is empty: {0}'.format(
                    args.file)
                return False
        except OSError as ex:
            print 'Could not open hex: {0}'.format(ex)
            return False

        # The type argument is lowercase for backwards compatibility reasons. However, all subsequent calls need the correct type
        module_type = args.type.upper()

        update_success = bootload_modules(module_type, args.file, logger)
    finally:
        if log_file is not None:
            log_file.close()

    return update_success
Пример #34
0
        name for name in os.listdir(plugin_dir)
        if os.path.isdir(os.path.join(plugin_dir, name))
    ]
    for plugin in plugins:
        shutil.rmtree(plugin_dir + plugin)

    config_files = constants.get_plugin_configfiles()
    for config_file in glob.glob(config_files):
        os.remove(config_file)


if __name__ == '__main__':
    setup_logger()

    config = ConfigParser()
    config.read(constants.get_config_file())

    Injectable.value(config_db_lock=Lock())
    Injectable.value(config_db=constants.get_config_database_file())
    Injectable.value(eeprom_db=constants.get_eeprom_extension_database_file())

    controller_serial_port = config.get('OpenMotics', 'controller_serial')
    Injectable.value(controller_serial=Serial(controller_serial_port, 115200))

    from gateway import config as config_controller
    _ = config_controller
    if Platform.get_platform() == Platform.Type.CORE_PLUS:
        from gateway.hal import master_controller_core  # type: ignore
        from master_core import maintenance, core_communicator, ucan_communicator  # type: ignore
        _ = master_controller_core, maintenance, core_communicator, ucan_communicator  # type: ignore
    else:
Пример #35
0
def main():
    """ Main function. """
    config = ConfigParser()
    config.read(constants.get_config_file())

    defaults = {
        'username': config.get('OpenMotics', 'cloud_user'),
        'password': config.get('OpenMotics', 'cloud_pass')
    }

    user_controller = UserController(constants.get_user_database_file(),
                                     defaults, 3600)

    led_service = LedService()

    controller_serial_port = config.get('OpenMotics', 'controller_serial')
    passthrough_serial_port = config.get('OpenMotics', 'passthrough_serial')
    power_serial_port = config.get('OpenMotics', 'power_serial')

    controller_serial = Serial(controller_serial_port, 115200)
    passthrough_serial = Serial(passthrough_serial_port, 115200)
    power_serial = RS485(Serial(power_serial_port, 115200, timeout=None))

    master_communicator = MasterCommunicator(controller_serial)
    master_communicator.start()

    power_controller = PowerController(constants.get_power_database_file())

    power_communicator = PowerCommunicator(power_serial, power_controller)
    power_communicator.start()

    gateway_api = GatewayApi(master_communicator, power_communicator,
                             power_controller)

    maintenance_service = MaintenanceService(
        gateway_api, constants.get_ssl_private_key_file(),
        constants.get_ssl_certificate_file())

    passthrough_service = PassthroughService(master_communicator,
                                             passthrough_serial)
    passthrough_service.start()

    web_interface = WebInterface(user_controller, gateway_api,
                                 constants.get_scheduling_database_file(),
                                 maintenance_service,
                                 led_service.in_authorized_mode)

    plugin_controller = PluginController(web_interface)
    plugin_controller.start_plugins()

    web_interface.set_plugin_controller(plugin_controller)
    gateway_api.set_plugin_controller(plugin_controller)

    web_service = WebService(web_interface)
    web_service.start()

    led_service.set_led('stat2', True)

    led_thread = threading.Thread(target=led_driver,
                                  args=(led_service, master_communicator,
                                        power_communicator))
    led_thread.setName("Serial led driver thread")
    led_thread.daemon = True
    led_thread.start()

    def stop(signum, frame):
        """ This function is called on SIGTERM. """
        sys.stderr.write("Shutting down")
        led_service.set_led('stat2', False)
        web_service.stop()

    signal(SIGTERM, stop)
Пример #36
0
    def build_graph():
        config = ConfigParser()
        config.read(constants.get_config_file())

        config_lock = Lock()
        scheduling_lock = Lock()
        metrics_lock = Lock()

        config_database_file = constants.get_config_database_file()

        # TODO: Clean up dependencies more to reduce complexity

        # IOC announcements
        # When below modules are imported, the classes are registerd in the IOC graph. This is required for
        # instances that are used in @Inject decorated functions below, and is also needed to specify
        # abstract implementations depending on e.g. the platform (classic vs core) or certain settings (classic
        # thermostats vs gateway thermostats)
        from power import power_communicator, power_controller
        from plugins import base
        from gateway import (metrics_controller, webservice, scheduling,
                             observer, gateway_api, metrics_collector,
                             maintenance_controller, comm_led_controller,
                             users, pulses, config as config_controller,
                             metrics_caching, watchdog)
        from cloud import events
        _ = (metrics_controller, webservice, scheduling, observer, gateway_api,
             metrics_collector, maintenance_controller, base, events,
             power_communicator, comm_led_controller, users, power_controller,
             pulses, config_controller, metrics_caching, watchdog)
        if Platform.get_platform() == Platform.Type.CORE_PLUS:
            from gateway.hal import master_controller_core
            from master_core import maintenance, core_communicator, ucan_communicator
            from master import eeprom_extension  # TODO: Obsolete, need to be removed
            _ = master_controller_core, maintenance, core_communicator, ucan_communicator
        else:
            from gateway.hal import master_controller_classic
            from master import maintenance, master_communicator, eeprom_extension
            _ = master_controller_classic, maintenance, master_communicator, eeprom_extension

        thermostats_gateway_feature = Feature.get_or_none(
            name='thermostats_gateway')
        thermostats_gateway_enabled = thermostats_gateway_feature is not None and thermostats_gateway_feature.enabled
        if Platform.get_platform(
        ) == Platform.Type.CORE_PLUS or thermostats_gateway_enabled:
            from gateway.thermostat.gateway import thermostat_controller_gateway
            _ = thermostat_controller_gateway
        else:
            from gateway.thermostat.master import thermostat_controller_master
            _ = thermostat_controller_master

        # IPC
        Injectable.value(message_client=MessageClient('openmotics_service'))

        # Cloud API
        parsed_url = urlparse(config.get('OpenMotics', 'vpn_check_url'))
        Injectable.value(gateway_uuid=config.get('OpenMotics', 'uuid'))
        Injectable.value(cloud_endpoint=parsed_url.hostname)
        Injectable.value(cloud_port=parsed_url.port)
        Injectable.value(cloud_ssl=parsed_url.scheme == 'https')
        Injectable.value(cloud_api_version=0)

        # User Controller
        Injectable.value(user_db=config_database_file)
        Injectable.value(user_db_lock=config_lock)
        Injectable.value(token_timeout=3600)
        Injectable.value(
            config={
                'username': config.get('OpenMotics', 'cloud_user'),
                'password': config.get('OpenMotics', 'cloud_pass')
            })

        # Configuration Controller
        Injectable.value(config_db=config_database_file)
        Injectable.value(config_db_lock=config_lock)

        # Energy Controller
        power_serial_port = config.get('OpenMotics', 'power_serial')
        Injectable.value(power_db=constants.get_power_database_file())
        if power_serial_port:
            Injectable.value(power_serial=RS485(
                Serial(power_serial_port, 115200, timeout=None)))
        else:
            Injectable.value(power_serial=None)
            Injectable.value(power_communicator=None)
            Injectable.value(power_controller=None)

        # Pulse Controller
        Injectable.value(pulse_db=constants.get_pulse_counter_database_file())

        # Scheduling Controller
        Injectable.value(
            scheduling_db=constants.get_scheduling_database_file())
        Injectable.value(scheduling_db_lock=scheduling_lock)

        # Master Controller
        controller_serial_port = config.get('OpenMotics', 'controller_serial')
        Injectable.value(
            controller_serial=Serial(controller_serial_port, 115200))
        if Platform.get_platform() == Platform.Type.CORE_PLUS:
            from master_core.memory_file import MemoryFile, MemoryTypes
            core_cli_serial_port = config.get('OpenMotics', 'cli_serial')
            Injectable.value(cli_serial=Serial(core_cli_serial_port, 115200))
            Injectable.value(passthrough_service=None)  # Mark as "not needed"
            Injectable.value(
                memory_files={
                    MemoryTypes.EEPROM: MemoryFile(MemoryTypes.EEPROM),
                    MemoryTypes.FRAM: MemoryFile(MemoryTypes.FRAM)
                })
            # TODO: Remove; should not be needed for Core
            Injectable.value(
                eeprom_db=constants.get_eeprom_extension_database_file())
        else:
            passthrough_serial_port = config.get('OpenMotics',
                                                 'passthrough_serial')
            Injectable.value(
                eeprom_db=constants.get_eeprom_extension_database_file())
            if passthrough_serial_port:
                Injectable.value(
                    passthrough_serial=Serial(passthrough_serial_port, 115200))
                from master.passthrough import PassthroughService
                _ = PassthroughService  # IOC announcement
            else:
                Injectable.value(passthrough_service=None)

        # Metrics Controller
        Injectable.value(metrics_db=constants.get_metrics_database_file())
        Injectable.value(metrics_db_lock=metrics_lock)

        # Webserver / Presentation layer
        Injectable.value(ssl_private_key=constants.get_ssl_private_key_file())
        Injectable.value(ssl_certificate=constants.get_ssl_certificate_file())