async def test_start_from_async_stop_from_executor(): with patch("pyhap.accessory_driver.HAPServer.async_stop", new_callable=AsyncMock), patch( "pyhap.accessory_driver.HAPServer.async_start", new_callable=AsyncMock ), patch("pyhap.accessory_driver.Zeroconf"), patch( "pyhap.accessory_driver.AccessoryDriver.persist"), patch( "pyhap.accessory_driver.AccessoryDriver.load"): driver = AccessoryDriver(loop=asyncio.get_event_loop()) run_event = asyncio.Event() class Acc(Accessory): @Accessory.run_at_interval(0) def run(self): # pylint: disable=invalid-overridden-method run_event.set() def setup_message(self): pass acc = Acc(driver, "TestAcc") driver.add_accessory(acc) driver.start_service() await run_event.wait() assert not driver.loop.is_closed() await driver.loop.run_in_executor(None, driver.stop) await driver.aio_stop_event.wait()
def create_driver(loop, core_alarm): config = core_alarm.config.get('homekit', {}) use_bridge = core_alarm.sensors or config.get('use_bridge', False) driver = AccessoryDriver(loop=loop, port=config.get('port', 51001)) alarm = Alarm(driver, core_alarm, config) alarm.set_info_service(model=core_alarm.model, manufacturer='Jablotron', serial_number=core_alarm.serial_number, firmware_revision=core_alarm.firmware_version) if use_bridge: bridge = Bridge(driver, display_name='Jablotron Bridge') bridge.set_info_service(model=core_alarm.model, manufacturer='Jablotron', serial_number=core_alarm.serial_number, firmware_revision=core_alarm.firmware_version) bridge.add_accessory(alarm) for s in core_alarm.sensors.values(): bridge.add_accessory(create_sensor_accessory(driver, s)) driver.add_accessory(bridge) else: driver.add_accessory(alarm) return driver
async def test_start_stop_async_acc(): """Verify run_at_interval closes the driver.""" with patch("pyhap.accessory_driver.HAPServer.async_stop", new_callable=AsyncMock), patch( "pyhap.accessory_driver.HAPServer.async_start", new_callable=AsyncMock ), patch("pyhap.accessory_driver.Zeroconf"), patch( "pyhap.accessory_driver.AccessoryDriver.persist"), patch( "pyhap.accessory_driver.AccessoryDriver.load"): driver = AccessoryDriver(loop=asyncio.get_event_loop()) run_event = asyncio.Event() class Acc(Accessory): @Accessory.run_at_interval(0) async def run(self): run_event.set() def setup_message(self): pass acc = Acc(driver, "TestAcc") driver.add_accessory(acc) driver.start_service() await asyncio.sleep(0) await run_event.wait() assert not driver.loop.is_closed() await driver.async_stop() assert not driver.loop.is_closed()
def main(): # init logger logger = logging.getLogger('homekit-flux-led') formatter = logging.Formatter('[%(levelname)s %(asctime)s]: %(message)s') ch = logging.StreamHandler() ch.setFormatter(formatter) logger.addHandler(ch) # parse cli-arguments parser = argparse.ArgumentParser() parser.add_argument( '-v', '--verbose', help='DEBUG logging mode', action='store_true', ) args = parser.parse_args() # set loggin level if args.verbose: logger.setLevel(logging.DEBUG) logger.info('Logging level: DEBUG') else: logger.setLevel(logging.INFO) logger.info('Logging level: INFO') # scan for bulbs logger.debug('Scanning for lightbulbs') scanner = BulbScanner() scanner.scan() logger.debug(f'Found lightbulbs:') logger.debug(scanner.found_bulbs) # initialize AccessoryServer logger.debug('Create HomeKit-AccessoryServer...') driver = AccessoryDriver() bridge = Bridge(driver, 'MagicHome') logger.debug('HomeKit-AccessoryServer created successful.') for bulb in scanner.found_bulbs: # add bulbs to bridge logger bridge.add_accessory( FluxLED( driver, bulb['id'], bulb['ipaddr'], logger=logger, ), ) # add bridge to the driver driver.add_accessory(bridge) try: # start the server logger.info('Start server...') driver.start() except KeyboardInterrupt: logger.info('Stopping server...') driver.stop()
async def test_start_service_and_update_config(): """Test starting service and updating the config.""" with patch("pyhap.accessory_driver.HAPServer.async_stop", new_callable=AsyncMock), patch( "pyhap.accessory_driver.HAPServer.async_start", new_callable=AsyncMock ), patch("pyhap.accessory_driver.Zeroconf"), patch( "pyhap.accessory_driver.AccessoryDriver.persist"), patch( "pyhap.accessory_driver.AccessoryDriver.load"): driver = AccessoryDriver(loop=asyncio.get_event_loop()) acc = Accessory(driver, "TestAcc") driver.add_accessory(acc) await driver.async_start() assert driver.state.config_version == 2 driver.config_changed() assert driver.state.config_version == 3 driver.state.config_version = 65535 driver.config_changed() assert driver.state.config_version == 1 for _ in range(3): await asyncio.sleep(0) await driver.async_stop() await asyncio.sleep(0) assert not driver.loop.is_closed() assert driver.aio_stop_event.is_set()
async def test_bridge_with_multiple_sync_run_at_interval_accessories(): with patch("pyhap.accessory_driver.HAPServer.async_stop", new_callable=AsyncMock), patch( "pyhap.accessory_driver.HAPServer.async_start", new_callable=AsyncMock ), patch("pyhap.accessory_driver.Zeroconf"), patch( "pyhap.accessory_driver.AccessoryDriver.persist"), patch( "pyhap.accessory_driver.AccessoryDriver.load"): driver = AccessoryDriver(loop=asyncio.get_event_loop()) bridge = Bridge(driver, "mybridge") acc = SyncIntervalAccessory(driver, "TestAcc", aid=2) acc2 = SyncIntervalAccessory(driver, "TestAcc2", aid=3) acc3 = SyncIntervalAccessory(driver, "TestAcc3", aid=4) bridge.add_accessory(acc) bridge.add_accessory(acc2) bridge.add_accessory(acc3) driver.add_accessory(bridge) driver.start_service() await asyncio.sleep(0.5) assert not driver.loop.is_closed() await driver.async_stop() assert acc.counter > 2 assert acc2.counter > 2 assert acc3.counter > 2
def start_homekit(co2meter): # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=CO2Sensor( co2meter=co2meter, driver=driver, display_name="CO2 Sensor")) # We want SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
def main(args): import logging import signal from pyhap.accessory_driver import AccessoryDriver logging.basicConfig(level=logging.INFO) driver = AccessoryDriver(port=args.port) accessory = MiFan(args, driver, 'Fanv2') driver.add_accessory(accessory=accessory) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
def homekit(): # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) # Change `get_accessory` to `get_bridge` if you want to run a Bridge. driver.add_accessory(accessory=get_accessory(driver)) # We want SIGTERM (kill) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
def main(): import logging import signal from pyhap.accessory_driver import AccessoryDriver logging.basicConfig(level=logging.INFO) driver = AccessoryDriver(port=51826) accessory = TV(driver, 'TV') driver.add_accessory(accessory=accessory) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
class GardenHub(): hub_name = None driver = None bridge = None coup = None def __init__(self, hub_name, user, device, listen_address=None): logging.basicConfig(level=logging.INFO, format="[%(module)s] %(message)s") # Initialize my coup self.hub_name = hub_name coup = RemoteCoup(user, device) # Start the accessory on port 51826 if listen_address: self.driver = AccessoryDriver(port=51826, address=listen_address) else: self.driver = AccessoryDriver(port=51826) self.bridge = Bridge(self.driver, self.hub_name) # Setup run and coup lights while True: status = coup.get_status() if (status is None) or ('Coup' not in status) or ('Lights' not in status['Coup']): logger.error("Status has not been initialized or lights missing: Status = {0} at {1}".format(status, datetime.now())) else: for light in status['Coup']['Lights']: logger.info("Adding %s", light) runlight = RemoteGardenLight(self.driver, name=light, coup=coup) self.bridge.add_accessory(runlight) break time.sleep(5) # Change `get_accessory` to `get_bridge` if you want to run a Bridge. self.driver.add_accessory(accessory=self.bridge) # We want SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, self.driver.signal_handler) def start(self): self.driver.start() print("Completed {0} start".format(__name__))
async def test_we_can_connect(): """Test we can start, connect, and stop.""" loop = asyncio.get_event_loop() with patch("pyhap.accessory_driver.Zeroconf"), patch( "pyhap.accessory_driver.AccessoryDriver.persist" ): driver = AccessoryDriver(loop=loop) driver.add_accessory(Accessory(driver, "TestAcc")) addr_info = ("0.0.0.0", None) server = hap_server.HAPServer(addr_info, driver) await server.async_start(loop) sock = server.server.sockets[0] assert server.connections == {} _, port = sock.getsockname() _, writer = await asyncio.open_connection("127.0.0.1", port) assert server.connections != {} server.async_stop() writer.close()
def main(cfg, reset, setup_systemd): # init logging logging.basicConfig(level=logging.INFO) if reset: # remove accessory.state os.remove('accessory.state') if setup_systemd: systmd() # create config if necessary if not os.path.exists(os.path.join(cfg, 'bridge.cfg')): create_cfg(cfg) # start the accessory driver on port 51826 driver = AccessoryDriver(port=51826) # create bridge bridge = MqttBridge(cfg, driver, 'MQTT') # load accs loader = cfg_loader.CfgLoader(driver, cfg) accs = loader.load_accessories(reset) for acc in accs: bridge.add_accessory(acc) loader.save_accessories() # add the bridge driver.add_accessory(accessory=bridge) signal.signal(signal.SIGTERM, driver.signal_handler) # start HomeKit driver.start() print('Returned') return 0
def start(self): try: logging.basicConfig(level=logging.INFO) driver = AccessoryDriver(port=51827) bridge = Bridge(driver, 'Bridge') for device in self.settings.xcomfort.devices: if not device.add_to_homekit: continue print(f"[XComfort] Adding {device.name}") lamp = HomeKitXComfortLight(driver, device.name) bridge.add_accessory(lamp) for device in self.settings.easee.devices: if not device.add_to_homekit: continue print(f"[Easee] Adding {device.name}") charger = EaseeCharger(driver, device.name) bridge.add_accessory(charger) driver.add_accessory(accessory=bridge) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() except KeyboardInterrupt: print('Stopping...')
LED_DMA = 10 # DMA channel to use for generating signal (try 10) LED_BRIGHTNESS = 200 # Set to 0 for darkest and 255 for brightest LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 LED_STRIP = ws.SK6812W_STRIP strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP) strip.begin() def get_bridge(driver): """Call this method to get a Bridge instead of a standalone accessory.""" bridge = Bridge(driver, 'Bridge') music_dis = MusicStart(strip, driver, 'MusicDisplay') bridge.add_accessory(music_dis) return bridge # Start the accessory on port 51828 driver = AccessoryDriver(port=51828, persist_file='main.state') # Change `get_accessory` to `get_bridge` if you want to run a Bridge. driver.add_accessory(accessory=get_bridge(driver)) # We want SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
maxNr=140, minNr=20, minDevPerc=2.0) bridge.add_sampler(sampler, conf.itstore) if __name__ == "__main__": logger = logging.getLogger() hand = logging.StreamHandler() hand.setLevel(logging.INFO) logger.addHandler(hand) # use console logger.addHandler( logging.FileHandler(filename='p1DSMR_Hap.log', mode='w', encoding='utf-8')) logger.setLevel(logging.DEBUG) logger.critical("### running %s dd %s ###" % (__file__, time.strftime("%y%m%d %H:%M:%S"))) driver = AccessoryDriver(port=51826) bridge = fsBridge(driver, 'fsBridge') add_p1DSMR_to_bridge(bridge, config="p1DSMR.json") driver.add_accessory(accessory=bridge) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() logger.info('bye')
# [480, 270, 30], # [320, 240, 30], # [320, 180, 30], ], }, "audio": { "codecs": [{ 'type': 'OPUS', 'samplerate': 24, }, { 'type': 'AAC-eld', 'samplerate': 16 }], }, "srtp": True, # hard code the address if auto-detection does not work as desired: e.g. "192.168.1.226" "address": util.get_local_address(), "start_stream_cmd": FFMPEG_CMD } # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) acc = camera.Camera(options, driver, "Camera") driver.add_accessory(accessory=acc) # We want KeyboardInterrupts and SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
def run(): driver = AccessoryDriver(port=51826, persist_file='busy_home.state') driver.add_accessory(accessory=get_bridge(driver)) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
logging.basicConfig(level=logging.DEBUG) driver = AccessoryDriver(port=54321, pincode=bytearray(b'111-11-111'), mac=util.generate_mac()) bridge = Bridge(driver, 'Bridge') air_quality = AirQualityMonitor(driver, 'Air Monitor', ip='192.168.1.1', token='XXX') bridge.add_accessory(air_quality) vacuum = Vacuum(driver, 'Vacuum', ip='192.168.1.2', token='XXX') bridge.add_accessory(vacuum) air_fresh = AirFresh(driver, 'Air Fresh', ip='192.168.1.3', token='XXX') bridge.add_accessory(air_fresh) nikolay_at_home = Presence(driver, 'Nikolay', hostname='192.168.1.4') bridge.add_accessory(nikolay_at_home) trigger = DummySwitch(driver, 'Trigger') bridge.add_accessory(trigger) driver.add_accessory(bridge) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() print('Bridge Ready')
port = int(arg) if opt in ['-u', '--updates']: dev_updates = True logging.info("Bridge name: %s", bridge_name) loop = asyncio.get_event_loop() try: xknx = loop.run_until_complete(get_xknx(config_file, dev_updates)) except Exception as e: logging.info('Exception for KNX: %s', e) logging.info('Exiting...') sys.exit(1) driver = AccessoryDriver(loop=loop, port=port, persist_file='homekit-knx-bridge.state') driver.add_accessory( accessory=get_bridge_from_config(driver, bridge_name, xknx)) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() #driver.async_add_job(xknx.start()) #driver.add_job(xknx.stop()) #loop.run_until_complete(xknx.stop()) # driver.stop()
"""Demo script for starting.""" import logging import signal from pyhap.accessory_driver import AccessoryDriver from py_maxcube import MaxBridge logging.basicConfig(level=logging.INFO, format="[%(module)s] %(message)s") driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=MaxBridge('192.168.1.247', 62910, driver, 'MaxBridge')) # We want SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
"""An example of how to setup and start an Accessory. This is: 1. Create the Accessory object you want. 2. Add it to an AccessoryDriver, which will advertise it on the local network, setup a server to answer client queries, etc. """ import logging import signal from pyhap.accessory_driver import AccessoryDriver import pyhap.loader as loader # The below package can be found in the HAP-python github repo under accessories/ from LightBulb import LightBulb logging.basicConfig(level=logging.INFO) # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) # Change `get_accessory` to `get_bridge` if you want to run a Bridge. driver.add_accessory(accessory=LightBulb(driver, 'Deck Lights')) # We want SIGTERM (kill) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
wihome_client=inst['wihome_client'], wihome_channel=inst['wihome_channel'])) elif acc['accessory'] == 'WiHomeGateOpener': for inst in acc['instances']: bridge.add_accessory( WiHomeGateOpener(_driver, inst['homekit_label'], wihome_instance=wihome, wihome_client=inst['wihome_client'])) elif acc['accessory'] == 'WiHomeGateOpenerSetup': for inst in acc['instances']: bridge.add_accessory( WiHomeGateOpenerSetup( _driver, inst['homekit_label'], wihome_instance=wihome, wihome_parameter=inst['wihome_parameter'], wihome_scaling_0=inst['wihome_scaling_0'], wihome_scaling_100=inst['wihome_scaling_100'], wihome_client=inst['wihome_client'])) return bridge wh = WiHome() driver = AccessoryDriver(port=51826, persist_file='wihome.state') driver.add_accessory(accessory=get_bridge(driver, wihome=wh)) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
self.char_on.set_value(value=v) self.setBulb(v) def get_bridge(driver): bridge = Bridge(driver, 'Bridge') for lName in lampNames: lamp = Lamp(driver, lName) bridge.add_accessory(lamp) return bridge # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) myBridge = get_bridge(driver) driver.add_accessory(accessory=myBridge) signal.signal(signal.SIGTERM, driver.signal_handler) def message_delegate(message): asStr = str(message, 'utf-8') for _, accessory in myBridge.accessories.items(): if accessory.display_name == asStr: accessory.flipBulb() def onSwitchChanged(state): for lampName, isOn in state.items(): for _, accessory in myBridge.accessories.items(): if accessory.display_name == lampName: accState = bool(accessory.char_on.value)
test.add_service(service_loader.get_service("Switch")) accessories = list() accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_1", aid=1111)) accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_2", aid=2222)) accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_3", aid=3333)) accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_4", aid=4444)) accessories.append(TemperatureSensor(driver, "fake_temp")) # accessories.append(test) # MqttAccessories(TemperatureSensor(MQTTSERVER, driver, "Battery_1", aid=2323)) # MqttAccessories.accessories[2].add_service(service_loader.get_service("BatteryService")) # Add the accessories and the topics to the mqtt bridge for acc in accessories: mqtt_bridge.add_accessory(acc) try: mqtt_bridge.add_topic(acc.topic) except AttributeError: pass driver.add_accessory(accessory=mqtt_bridge) # driver.add_accessory(accessory=TemperatureSensor(driver, "fake_temp")) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
import signal import logging import busio from pyhap.accessory_driver import AccessoryDriver from pyhap.const import CATEGORY_SWITCH from adafruit_pca9685 import PCA9685 from board import SCL, SDA from python_json_config import ConfigBuilder from dusty.dusty import DustyBridge, DustySwitch logging.basicConfig(level=logging.INFO, format="[%(module)s] %(message)s") logger = logging.getLogger() builder = ConfigBuilder() config = builder.parse_config('config.json') i2c = busio.I2C(SCL, SDA) pca = PCA9685(i2c) pca = PCA9685(i2c, reference_clock_speed=config.servo.reference_clock_speed) pca.frequency = config.servo.frequency driver = AccessoryDriver(port=config.dusty.port) dusty_bridge = DustyBridge(driver, config.dusty.max_switches, pca, config) driver.add_accessory(accessory=dusty_bridge) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()
def main(getter, setter, port): driver = AccessoryDriver(port=port) driver.add_accessory(accessory=AirConditioner(getter, setter, driver, 'ElectraAirConditioner')) signal.signal(signal.SIGTERM, driver.signal_handler) return driver
def set_bulb(self, value): print("Setting bulb state to %s" % value) global isPowered isPowered = not isPowered if value: relay.off() else: relay.on() def stop(self): super().stop() driver = AccessoryDriver(port=51826) driver.add_accessory(accessory=HomekitDevice(driver, 'Light 1')) signal.signal(signal.SIGTERM, driver.signal_handler) driver.start() dir = os.getcwd() @app.route('/', methods=['GET', 'POST']) def main(): return render_template('index.html', isPowered=isPowered) @app.route('/handle_data', methods=['POST']) def handle_data():
self.char_temp.set_value(random.randint(18, 26)) def get_bridge(driver): """Call this method to get a Bridge instead of a standalone accessory.""" bridge = Bridge(driver, 'Bridge') temp_sensor = TemperatureSensor(driver, 'Sensor 2') temp_sensor2 = TemperatureSensor(driver, 'Sensor 1') bridge.add_accessory(temp_sensor) bridge.add_accessory(temp_sensor2) return bridge def get_accessory(driver): """Call this method to get a standalone Accessory.""" return TemperatureSensor(driver, 'MyTempSensor') # Start the accessory on port 51826 driver = AccessoryDriver(port=51826) # Change `get_accessory` to `get_bridge` if you want to run a Bridge. driver.add_accessory(accessory=get_accessory(driver)) # We want SIGTERM (terminate) to be handled by the driver itself, # so that it can gracefully stop the accessory, server and advertising. signal.signal(signal.SIGTERM, driver.signal_handler) # Start it! driver.start()
def main(): # noqa: C901 pylint: disable=too-many-branches, too-many-statements, too-many-locals parser = argparse.ArgumentParser(prog='vwsfriend', description='TBD') parser.add_argument( '--version', action='version', version= f'%(prog)s {__version__} (using WeConnect-python {__weconnect_version__})' ) parser.add_argument('-u', '--username', help='Username of VWsFriend UI', required=False) parser.add_argument('-p', '--password', help='Password of VWsFriend UI', required=False) parser.add_argument('--host', help='Host of VWsFriend UI', type=str, required=False, default='0.0.0.0') # nosec parser.add_argument('--port', help='Port of VWsFriend UI', type=int, choices=range(1, 65535), metavar="[1-65535]", required=False, default=4000) weConnectGroup = parser.add_argument_group('WeConnect') weConnectGroup.add_argument('--weconnect-username', dest='weConnectUsername', help='Username of Volkswagen id', required=False) weConnectGroup.add_argument('--weconnect-password', dest='weConnectPassword', help='Password of Volkswagen id', required=False) defaultNetRc = os.path.join(os.path.expanduser("~"), ".netrc") weConnectGroup.add_argument( '--netrc', help=f'File in netrc syntax providing login (default: {defaultNetRc}).' ' Netrc is only used when username and password are not provided as arguments', default=None, required=False) weConnectGroup.add_argument('-i', '--interval', help='Query interval in seconds', type=NumberRangeArgument(imin=180), required=False, default=300) defaultTemp = os.path.join(tempfile.gettempdir(), 'weconnect.token') weConnectGroup.add_argument( '--tokenfile', help=f'file to store token (default: {defaultTemp})', default=defaultTemp) weConnectGroup.add_argument( '--no-token-storage', dest='noTokenStorage', help='Do not store token on filesystem (this' ' will cause a new login for every invokation!)', action='store_true') parser.add_argument( '--config-dir', dest='configDir', help='directory to store configuration files (default: ./)', default='./') parser.add_argument( '--demo', help='folder containing demo scenario, see README for more information' ) parser.add_argument('--privacy', help='Options to control privacy of the cars users', default=[], required=False, action='append', type=Privacy, choices=list(Privacy)) dbGroup = parser.add_argument_group('Database & visualization') dbGroup.add_argument( '--with-database', dest='withDatabase', help='Connect VWsFriend to database for visualization', action='store_true') dbGroup.add_argument('--database-url', dest='dbUrl', help='Database to connect to', default='sqlite:///vwsfrienddevel.db') abrpGroup = parser.add_argument_group('ABRP: A better route planner') abrpGroup.add_argument( '--with-abrp', dest='withABRP', help= 'Connect VWsFriend to ABRP (you need to add userTokens in the UI!)', action='store_true') homekitGroup = parser.add_argument_group('Homekit') homekitGroup.add_argument('--with-homekit', dest='withHomekit', help='Provide Apple Homekit functionality', action='store_true') loggingGroup = parser.add_argument_group('Logging') loggingGroup.add_argument( '-v', '--verbose', action="append_const", help='Logging level (verbosity)', const=-1, ) loggingGroup.add_argument( '--logging-format', dest='loggingFormat', help='Logging format configured for python logging ' '(default: %%(asctime)s:%%(levelname)s:%%(module)s:%%(message)s)', default='%(asctime)s:%(levelname)s:%(module)s:%(message)s') loggingGroup.add_argument( '--logging-date-format', dest='loggingDateFormat', help='Logging format configured for python logging ' '(default: %%Y-%%m-%%dT%%H:%%M:%%S%%z)', default='%Y-%m-%dT%H:%M:%S%z') loggingGroup.add_argument( '--hide-repeated-log', dest='hideRepeatedLog', help='Hide repeated log messages from the same module', action='store_true') loggingMailGroup = parser.add_argument_group( 'Logging to Email (Errors only)') loggingMailGroup.add_argument('--logging-mail-from', dest='loggingMailFrom', help='Mail address to send mails from', required=False) loggingMailGroup.add_argument( '--logging-mail-to', dest='loggingMailTo', help='Mail address to send mails to (can be used multiple times)', required=False, action='append') loggingMailGroup.add_argument('--logging-mail-host', dest='loggingMailHost', help='Mail server host', required=False) loggingMailGroup.add_argument('--logging-mail-credentials', dest='loggingMailCredentials', help='Mail server credentials', required=False, nargs=2) loggingMailGroup.add_argument('--logging-mail-subject', dest='loggingMailSubject', help='Mail subject', required=False, default='VWsFriend Log') loggingMailGroup.add_argument('--logging-mail-notls', dest='loggingMailnotls', help='Mail do not use TLS', required=False, action='store_true') loggingMailGroup.add_argument('--logging-mail-testmail', dest='loggingMailTestmail', help='Try to send Testmail at startup', required=False, action='store_true') args = parser.parse_args() logLevel = LOG_LEVELS.index(DEFAULT_LOG_LEVEL) for adjustment in args.verbose or (): logLevel = min(len(LOG_LEVELS) - 1, max(logLevel + adjustment, 0)) logging.basicConfig(level=LOG_LEVELS[logLevel], format=args.loggingFormat, datefmt=args.loggingDateFormat) logging.getLogger("pyhap").setLevel(level=LOG_LEVELS[logLevel]) if args.hideRepeatedLog: for handler in logging.root.handlers: handler.addFilter(DuplicateFilter()) # logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO) if any(arg is not None for arg in [ args.loggingMailFrom, args.loggingMailTo, args.loggingMailHost, args.loggingMailCredentials ]): if all(arg is not None for arg in [ args.loggingMailFrom, args.loggingMailTo, args.loggingMailHost, args.loggingMailCredentials ]): secure = () if args.loggingMailnotls: secure = None smtpHandler = logging.handlers.SMTPHandler( mailhost=args.loggingMailHost, fromaddr=args.loggingMailFrom, toaddrs=args.loggingMailTo, subject=args.loggingMailSubject, credentials=args.loggingMailCredentials, secure=secure) smtpHandler.setLevel(logging.INFO) smtpHandler.setFormatter( logging.Formatter("%(asctime)s %(levelname)-5s %(message)s")) LOG.addHandler(smtpHandler) if args.loggingMailTestmail: msg = f'vwsfriend {__version__} (using WeConnect-python {__weconnect_version__})' smtpHandler.emit( logging.LogRecord('VWsFriend', logging.INFO, pathname=None, lineno=None, msg=msg, args=None, exc_info=None)) smtpHandler.setLevel(logging.ERROR) else: LOG.error( 'You need to provide all --logging-mail options to make mail work' ) sys.exit(1) LOG.info('vwsfriend %s (using WeConnect-python %s)', __version__, __weconnect_version__) username = None password = None if args.username is not None and args.password is not None: username = args.username password = args.password else: if args.netrc is not None: netRcFilename = args.netrc else: netRcFilename = defaultNetRc try: secrets = netrc.netrc(file=args.netrc) username, _, password = secrets.authenticators("VWsFriend") except netrc.NetrcParseError as err: LOG.error('Authentification using .netrc failed: %s', err) sys.exit(1) except TypeError: LOG.error( 'VWsFriend entry was not found in %s netrc-file. Create it or provide a username with --username and a password with --password' ' with --username', netRcFilename) sys.exit(1) except FileNotFoundError: LOG.error( '%s netrc-file was not found. Create it or provide a username with --username and a password with --password', netRcFilename) sys.exit(1) if args.weConnectUsername is not None and args.weConnectPassword is not None: weConnectUsername = args.weConnectUsername weConnectPassword = args.weConnectPassword else: if args.netrc is not None: netRcFilename = args.netrc else: netRcFilename = defaultNetRc try: secrets = netrc.netrc(file=args.netrc) weConnectUsername, _, weConnectPassword = secrets.authenticators( "volkswagen.de") except netrc.NetrcParseError as err: LOG.error('Authentification using .netrc failed: %s', err) sys.exit(1) except TypeError: weConnectUsername = username weConnectPassword = password LOG.warning( 'volkswagen.de entry was not found in %s netrc-file. Create it or provide a username with --weconnect-username and a password with' ' --weconnect-password', netRcFilename) except FileNotFoundError: weConnectUsername = username weConnectPassword = password LOG.warning( '%s netrc-file was not found. Create it or provide a username with --weconnect-username and a password with --weconnect-password', netRcFilename) tokenfile = None if not args.noTokenStorage: tokenfile = args.tokenfile weConnect = None try: weConnect = weconnect.WeConnect(username=weConnectUsername, password=weConnectPassword, tokenfile=tokenfile, updateAfterLogin=False, loginOnInit=(args.demo is None), maxAgePictures=86400) connector = AgentConnector(weConnect=weConnect, dbUrl=args.dbUrl, interval=args.interval, withDB=args.withDatabase, withABRP=args.withABRP, configDir=args.configDir, privacy=args.privacy) driver = None if args.withHomekit: LOG.info('Starting up Homekit') # Start the accessory on port 51826 driver = AccessoryDriver( pincode=None, persist_file=f'{args.configDir}/accessory.state') for characteristicKey, characteristic in CUSTOM_CHARACTERISTICS.items( ): driver.loader.char_types[characteristicKey] = characteristic bridge = VWsFriendBridge( driver=driver, weConnect=weConnect, accessoryConfigFile=f'{args.configDir}/accessory.config') driver.add_accessory(bridge) weConnectBridgeInitialized = False # Start it! hapThread = threading.Thread(target=driver.start) hapThread.start() # Enable status tracking: weConnect.enableTracker() ui = VWsFriendUI(weConnect=weConnect, connector=connector, homekitDriver=driver, dbUrl=args.dbUrl, configDir=args.configDir, username=username, password=password) ui.run(host=args.host, port=args.port) if args.demo is not None: utcDemoStart = datetime.utcnow().replace(tzinfo=timezone.utc, microsecond=0) for file in sorted(os.listdir(args.demo)): fileNameRegex = r'(?P<number>\d+)_(?P<delay>\d+)s(_(?P<stage>[^\.]+))?.cache.json' match = re.search(fileNameRegex, file) if match is not None: time.sleep(int(match.groupdict()['delay'])) stageFilePath = f'{args.demo}/{file}' with open(stageFilePath, mode='r', encoding='utf8') as fp: cacheString = fp.read() cacheString = re.sub( r'demodate\((?P<offset>[+-]?\d+)\)', lambda m: str(utcDemoStart + timedelta(seconds=int( m.groupdict()['offset']))).replace( '+00:00', 'Z'), cacheString) cacheString = re.sub( r'now\((?P<offset>[+-]?\d+)\)', lambda m: str(datetime.now() + timedelta( seconds=int(m.groupdict()['offset']))), cacheString) weConnect.fillCacheFromJsonString(cacheString, maxAge=2147483647) if args.withHomekit and not weConnectBridgeInitialized: weConnectBridgeInitialized = True bridge.update() weConnect.update(updateCapabilities=True, updatePictures=False) connector.commit() if match.groupdict()['stage'] is not None: LOG.info('Stage %s completed', match.groupdict()['stage']) else: LOG.info('Stage completed') LOG.info('Demo completed') else: starttime = time.time() permanentErrors = 0 while True: try: LOG.info('Updating data from WeConnect') weConnect.update(updateCapabilities=True, updatePictures=True, force=True) connector.commit() if args.withHomekit and not weConnectBridgeInitialized: weConnectBridgeInitialized = True bridge.update() sleeptime = args.interval - ( (time.time() - starttime) % args.interval) permanentErrors = 0 except weconnect.RetrievalError: LOG.error( 'Retrieval error during update. Will try again after configured interval of %ds', args.interval) except APICompatibilityError as e: sleeptime = min((args.interval * pow(2, permanentErrors)), 86400) LOG.critical( 'There was a problem when communicating with WeConnect. If this problem persists please open a bug report: %s,' ' will retry after %ds', e, sleeptime) permanentErrors += 1 # Execute exactly every interval but if it misses its deadline only after the next interval time.sleep(sleeptime) except AuthentificationError as e: LOG.critical( 'There was a problem when authenticating with WeConnect: %s', e) except APICompatibilityError as e: LOG.critical( 'There was a problem when communicating with WeConnect.' ' If this problem persists please open a bug report: %s', e) finally: if weConnect is not None: weConnect.disconnect()