def init(self, force_scan):
        settings_path = '/Settings/ModbusClient/' + self.name
        SETTINGS = {
            'devices': [settings_path + '/Devices', '', 0, 0],
            'autoscan': [settings_path + '/AutoScan', self.auto_scan, 0, 1],
        }

        self.dbusconn = private_bus()

        log.info('Waiting for localsettings')
        self.settings = SettingsDevice(self.dbusconn,
                                       SETTINGS,
                                       self.setting_changed,
                                       timeout=10)

        devices = filter(None, self.settings['devices'])
        self.update_devlist('', devices)

        if not self.keep_failed:
            self.failed = []

        scan = force_scan

        if not self.devices or self.failed:
            if self.settings['autoscan']:
                scan = True

        if scan:
            self.start_scan(force_scan)
Esempio n. 2
0
def initSettings(newSettings):
    global settings

    #   settingsDevice is the library class that handles the reading and setting of persistent settings
    settings = SettingsDevice(
        bus=dbus.SystemBus() if
        (platform.machine() == 'armv7l') else dbus.SessionBus(),
        supportedSettings=newSettings,
        eventCallback=handle_changed_setting)
Esempio n. 3
0
    def start(self):
        log.info('Waiting for localsettings')
        self.settings = SettingsDevice(self.dbus.dbusconn,
                                       hiber_settings,
                                       self.setting_changed,
                                       timeout=10)

        self.ser = serial.Serial(self.dev, self.rate)

        self.thread = threading.Thread(target=self.run)
        self.thread.start()
Esempio n. 4
0
    def __init__(self,
                 n2kfluidtype,
                 n2ktankinstance,
                 paths,
                 productname='Signal K tank',
                 connection='Signal K tank service'):
        self._dbus = dbusconnection()
        self._servicename = '%s_%s_%s_%s' % (
            APPLICATION_SERVICE_NAME, SIGNALK_SERVER.replace('.', '_').replace(
                ':', '_'), str(n2kfluidtype), str(n2ktankinstance))
        self._dbusservicename = 'com.victronenergy.tank.%s' % self._servicename
        self._paths = paths

        # Process settings and recover our VRM instance number
        appsettingspath = '%s/%s' % (SETTINGS_ROOT, APPLICATION_SERVICE_NAME)
        servicesettingspath = '%s/%s' % (SETTINGS_ROOT, self._servicename)
        proposedclassdeviceinstance = '%s:%s' % ('tank', n2ktankinstance)
        SETTINGS = {
            'instance': [
                servicesettingspath + '/ClassAndVrmInstance',
                proposedclassdeviceinstance, 0, 0
            ],
            'customname': [servicesettingspath + '/CustomName', '', 0, 0]
        }
        self._settings = SettingsDevice(self._dbus, SETTINGS,
                                        self._handlesettingschanged)

        self._dbusservice = VeDbusService(self._dbusservicename, self._dbus)
        self._dbusservice.add_path('/Mgmt/ProcessName', __file__)
        self._dbusservice.add_path(
            '/Mgmt/ProcessVersion',
            VERSION + ' on Python ' + platform.python_version())
        self._dbusservice.add_path('/Mgmt/Connection',
                                   'SignalK ' + self._settings['instance'])

        self._dbusservice.add_path('/DeviceInstance',
                                   self._settings['instance'].split(':')[1])
        self._dbusservice.add_path('/ProductId', 0)
        self._dbusservice.add_path('/ProductName', '')
        self._dbusservice.add_path('/FirmwareVersion', 0)
        self._dbusservice.add_path('/HardwareVersion', 0)
        self._dbusservice.add_path('/Connected', 1)

        for path, settings in self._paths.iteritems():
            self._dbusservice.add_path(
                path,
                settings['initial'],
                writeable=True,
                onchangecallback=self._handlechangedvalue)
Esempio n. 5
0
def main():

    log.info('starting ' + c.DRIVER_NAME)

    tty = parse_cmdline_args()
    sensor = ImtSiRs485Sensor(tty)

    hw_ver, fw_ver = sensor.identify()

    # add hw and fw version to the signals, they are mandatory
    signals = c.SIGNALS + [
        DbusSignal('/HardwareVersion', hw_ver),
        DbusSignal('/FirmwareVersion', fw_ver)
    ]

    service_name = c.SERVICE_NAME + '.' + tty
    watchdog_timeout = (c.UPDATE_INTERVAL + c.SERIAL_TIMEOUT) * 2

    # starting watchdog here, because with VeDbusServiceAsync we are going multi-threaded
    with Watchdog(watchdog_timeout) as watchdog, VeDbusServiceAsync(
            service_name, signals) as dbus:

        settings_for_tty = get_settings_for_tty(tty)
        settings = SettingsDevice(dbus.dbusconn, settings_for_tty, None)
        _is_subsensor_present = partial(is_subsensor_present, settings)

        # only the modbus signals are updated, the others are const
        modbus_signals = [s for s in signals if isinstance(s, ModbusSignal)]

        while True:

            watchdog.alive()  # signal the watchdog that we are still alive

            registers = sensor.read_modbus_registers()

            for s in modbus_signals:
                value = registers[s.reg_no]
                if s.signed and value & 0x8000:
                    value -= 0x10000
                value *= s.gain

                if _is_subsensor_present(s.dbus_path, value):
                    dbus[s.dbus_path] = value
                else:
                    dbus[s.dbus_path] = None

            log.debug('iteration completed, sleeping for ' +
                      str(c.UPDATE_INTERVAL) + ' seconds')
            sleep(c.UPDATE_INTERVAL)
Esempio n. 6
0
    def setUp(self):
        self.start_services('vebus')
        self.start_services('battery')
        #self.start_services('pvinverter')
        #self.start_services('solarcharger')

        self.bus = dbus.SessionBus(
        ) if 'DBUS_SESSION_BUS_ADDRESS' in os.environ else dbus.SystemBus()

        settings = {
            attrs[0]: attrs
            for attrs in [
                ['/Settings/System/TimeZone', 'Europe/Amsterdam', 0, 0],
                ['/Settings/Relay/Polarity', 0, 0, 1],
                ['/Settings/Relay/Function', 1, 0, 1],
                [
                    '/Settings/Generator0/BatteryService',
                    'com_victronenergy_battery_223/Dc/0', 0, 0
                ],
                ['/Settings/Generator0/QuietHours/Enabled', 0, 0, 1],
                ['/Settings/Generator0/QuietHours/StartTime', 0, 0, 0],
                ['/Settings/Generator0/QuietHours/EndTime', 0, 0, 0],
                ['/Settings/Generator0/MinimumRuntime', 0, 0, 0],
                ['/Settings/Generator0/TestRun/Enabled', 0, 0, 1],
                ['/Settings/Generator0/TestRun/RunTillBatteryFull', 0, 0, 1],
                ['/Settings/Generator0/TestRun/SkipRuntime', 0, 0, 0],
                ['/Settings/Generator0/TestRun/StartDate', 0, 0, 0],
                ['/Settings/Generator0/TestRun/StartTime', 0, 0, 0],
                ['/Settings/Generator0/TestRun/Interval', 0, 0, 0],
                ['/Settings/Generator0/TestRun/Duration', 0, 0, 0],
                ['/Settings/Generator0/AutoStartEnabled', 1, 0, 1],
                ['/Settings/Generator0/OnLossCommunication', 0, 0, 0],
                ['/Settings/Generator0/AccumulatedDaily', '', 0, 0],
                ['/Settings/Generator0/AccumulatedTotal', 0, 0, 0],
            ]
        }
        conditions = ("BatteryCurrent", "BatteryVoltage", "AcLoad")
        condition_defaults = {
            "StartValue": 0,
            "StopValue": 0,
            "StartTimer": 0,
            "StopTimer": 0,
            "Enabled": 0,
            "QuitHoursStartValue": 0,
            "QuitHoursStopValue": 0
        }
        for condition in conditions:
            for setting_suffix, default_value in condition_defaults.iteritems(
            ):
                setting_label = 'gen0' + condition + setting_suffix
                setting_path = '/Settings/Generator0/' + condition + '/' + setting_suffix
                settings[setting_label] = [setting_path, default_value, 0, 0]

        self.settings = SettingsDevice(
            bus=self.bus,
            supportedSettings=settings,
            eventCallback=self.handle_changed_setting)

        # dbusgenerator needs to be able to read the timezone setting, so the settings must already by added
        self.start_services('dbusgenerator')

        self._settingspath = 'com.victronenergy.settings'
        self._generatorpath = 'com.victronenergy.generator.startstop0'
        self.batteryservice = 'com.victronenergy.battery.tty22'
        self.vebusservice = 'com.victronenergy.vebus.tty23'
        self.solarchergerservice = 'com.victronenergy.solarcharger.tty33'
        self.pvinverterservice = 'com.victronenergy.pvinverter.test'
        self.systemcalcservice = 'com.victronenergy.system'

        self.retriesonerror = 30

        self.set_value(self._settingspath, "/Settings/Relay/Function", 1)
        self.fill_history()
        self.firstRun = False
        self.reset_all_conditons()
        if (platform.machine() == 'armv7l'):
            os.environ['TZ'] = self.get_value(self._settingspath,
                                              '/Settings/System/TimeZone')
Esempio n. 7
0
  def __init__(self):
    self.driver_start_time = datetime.now()

    # data from yaml config file
    self._cfg = self.get_config_data()
    _cfg_bms = self._cfg['BMSData']

    # TODO: use venus settings to define these values
    #Initial BMS values eventually read from settings.
    self._bms_data = BMSData(max_battery_voltage=_cfg_bms['max_battery_voltage'], \
      min_battery_voltage=_cfg_bms['min_battery_voltage'], low_battery_voltage=_cfg_bms['low_battery_voltage'], \
      charge_bulk_amps=_cfg_bms['charge_bulk_amps'], max_discharge_amps=_cfg_bms['max_discharge_amps'], \
      charge_absorb_voltage=_cfg_bms['charge_absorb_voltage'], charge_float_voltage=_cfg_bms['charge_float_voltage'], \
      time_min_absorb=_cfg_bms['time_min_absorb'], rebulk_voltage=_cfg_bms['rebulk_voltage'])

    self.bms_controller = BMSChargeController(charge_bulk_current=self._bms_data.charge_bulk_amps, \
      charge_absorb_voltage=self._bms_data.charge_absorb_voltage, charge_float_voltage=self._bms_data.charge_float_voltage, \
        time_min_absorb=self._bms_data.time_min_absorb, rebulk_voltage=self._bms_data.rebulk_voltage)
    ret = self.bms_controller.start_charging()

    # Have a mainloop, so we can send/receive asynchronous calls to and from dbus
    DBusGMainLoop(set_as_default=True)

    self._can_bus = False

    logger.debug("Can bus init")
    try :
      self._can_bus = can.interface.Bus(bustype=canBusType, channel=canBusChannel, bitrate=500000)
    except can.CanError as e:
     logger.error(e)

    logger.debug("Can bus init done")

    # Add the AcInput1 setting if it doesn't exist so that the grid data is reported
    # to the system by dbus-systemcalc-py service
    settings = SettingsDevice(
       bus=dbus.SystemBus(),# if (platform.machine() == 'armv7l') else dbus.SessionBus(),
       supportedSettings={
           'acinput': ['/Settings/SystemSetup/AcInput1', 1, 0, 1],
           },
       eventCallback=None)


		# Why this dummy? Because DbusMonitor expects these values to be there, even though we don't
		# need them. So just add some dummy data. This can go away when DbusMonitor is more generic.
    dummy = {'code': None, 'whenToLog': 'configChange', 'accessLevel': None}
    dbus_tree = {'com.victronenergy.system': 
      {'/Dc/Battery/Soc': dummy, '/Dc/Battery/Current': dummy, '/Dc/Battery/Voltage': dummy, \
        '/Dc/Pv/Current': dummy, '/Ac/PvOnOutput/L1/Power': dummy, '/Ac/PvOnOutput/L2/Power': dummy, }}

    self._dbusmonitor = self._create_dbus_monitor(dbus_tree, valueChangedCallback=self._dbus_value_changed)

    self._dbusservice = self._create_dbus_service()

    self._dbusservice.add_path('/Serial',        value=12345)

    # /SystemState/State   ->   0: Off
    #                      ->   1: Low power
    #                      ->   2: VE.Bus Fault condition
    #                      ->   3: Bulk charging
    #                      ->   4: Absorption charging
    #                      ->   5: Float charging
    #                      ->   6: Storage mode
    #                      ->   7: Equalisation charging
    #                      ->   8: Passthru
    #                      ->   9: Inverting
    #                      ->  10: Assisting
    #                      -> 256: Discharging
    #                      -> 257: Sustain
    self._dbusservice.add_path('/State',                   0)
    self._dbusservice.add_path('/Mode',                    3)
    self._dbusservice.add_path('/Ac/PowerMeasurementType', 0)

    # Create the inverter/charger paths
    self._dbusservice.add_path('/Ac/Out/L1/P',            -1)
    self._dbusservice.add_path('/Ac/Out/L2/P',            -1)
    self._dbusservice.add_path('/Ac/Out/L1/I',            -1)
    self._dbusservice.add_path('/Ac/Out/L2/I',            -1)
    self._dbusservice.add_path('/Ac/Out/L1/V',            -1)
    self._dbusservice.add_path('/Ac/Out/L2/V',            -1)
    self._dbusservice.add_path('/Ac/Out/L1/F',            -1)
    self._dbusservice.add_path('/Ac/Out/L2/F',            -1)
    self._dbusservice.add_path('/Ac/Out/P',               -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L1/P',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L2/P',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/P',          -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L1/V',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L2/V',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L1/F',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L2/F',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L1/I',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/L2/I',       -1)
    self._dbusservice.add_path('/Ac/ActiveIn/Connected',   1)
    self._dbusservice.add_path('/Ac/ActiveIn/ActiveInput', 0)
    self._dbusservice.add_path('/VebusError',              0)
    self._dbusservice.add_path('/Dc/0/Voltage',           -1)
    self._dbusservice.add_path('/Dc/0/Power',             -1)
    self._dbusservice.add_path('/Dc/0/Current',           -1)
    self._dbusservice.add_path('/Ac/NumberOfPhases',       2)
    self._dbusservice.add_path('/Alarms/GridLost',         0)

    # /VebusChargeState  <- 1. Bulk
    #                       2. Absorption
    #                       3. Float
    #                       4. Storage
    #                       5. Repeat absorption
    #                       6. Forced absorption
    #                       7. Equalise
    #                       8. Bulk stopped
    self._dbusservice.add_path('/VebusChargeState',        0)

    # Some attempts at logging consumption. Float of kwhr since driver start (i think)
    self._dbusservice.add_path('/Energy/GridToDc',         0)
    self._dbusservice.add_path('/Energy/GridToAcOut',      0)
    self._dbusservice.add_path('/Energy/DcToAcOut',        0)
    self._dbusservice.add_path('/Energy/AcIn1ToInverter',  0)
    self._dbusservice.add_path('/Energy/AcIn1ToAcOut',     0)
    self._dbusservice.add_path('/Energy/InverterToAcOut',  0)
    self._dbusservice.add_path('/Energy/Time',       timer())

    self._changed = True

    # create timers (time in msec)
    gobject.timeout_add(2000, exit_on_error, self._can_bus_txmit_handler)
    gobject.timeout_add(2000, exit_on_error, self._energy_handler)
    gobject.timeout_add(20, exit_on_error, self._parse_can_data_handler)
    def __init__(self, retries=300):
        self._bus = dbus.SystemBus() if (
            platform.machine() == 'armv7l' or 'DBUS_SESSION_BUS_ADDRESS'
            not in environ) else dbus.SessionBus()
        self.RELAY_GPIO_FILE = '/sys/class/gpio/gpio182/value'
        self.HISTORY_DAYS = 30
        # One second per retry
        self.RETRIES_ON_ERROR = retries
        self._testrun_soc_retries = 0
        self._last_counters_check = 0
        self._dbusservice = None
        self._starttime = 0
        self._manualstarttimer = 0
        self._last_runtime_update = 0
        self._timer_runnning = 0
        self._battery_measurement_voltage_import = None
        self._battery_measurement_current_import = None
        self._battery_measurement_soc_import = None
        self._battery_measurement_available = True
        self._vebusservice_high_temperature_import = None
        self._vebusservice_overload_import = None
        self._vebusservice = None
        self._vebusservice_available = False
        self._relay_state_import = None

        self._condition_stack = {
            'batteryvoltage': {
                'name': 'batteryvoltage',
                'reached': False,
                'boolean': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'battery'
            },
            'batterycurrent': {
                'name': 'batterycurrent',
                'reached': False,
                'boolean': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'battery'
            },
            'acload': {
                'name': 'acload',
                'reached': False,
                'boolean': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'vebus'
            },
            'inverterhightemp': {
                'name': 'inverterhightemp',
                'reached': False,
                'boolean': True,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'vebus'
            },
            'inverteroverload': {
                'name': 'inverteroverload',
                'reached': False,
                'boolean': True,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'vebus'
            },
            'soc': {
                'name': 'soc',
                'reached': False,
                'boolean': False,
                'timed': False,
                'valid': True,
                'enabled': False,
                'retries': 0,
                'monitoring': 'battery'
            }
        }

        # DbusMonitor expects these values to be there, even though we don need them. So just
        # add some dummy data. This can go away when DbusMonitor is more generic.
        dummy = {
            'code': None,
            'whenToLog': 'configChange',
            'accessLevel': None
        }

        # TODO: possible improvement: don't use the DbusMonitor it all, since we are only monitoring
        # a set of static values which will always be available. DbusMonitor watches for services
        # that come and go, and takes care of automatic signal subscribtions etc. etc: all not necessary
        # in this use case where we have fixed services names (com.victronenergy.settings, and c
        # com.victronenergy.system).
        self._dbusmonitor = DbusMonitor({
         'com.victronenergy.settings': {   # This is not our setting so do it here. not in supportedSettings
          '/Settings/Relay/Function': dummy,
          '/Settings/Relay/Polarity': dummy,
          '/Settings/System/TimeZone': dummy,
          },
         'com.victronenergy.system': {   # This is not our setting so do it here. not in supportedSettings
          '/Ac/Consumption/Total/Power': dummy,
          '/Ac/PvOnOutput/Total/Power': dummy,
          '/Ac/PvOnGrid/Total/Power': dummy,
          '/Ac/PvOnGenset/Total/Power': dummy,
          '/Dc/Pv/Power': dummy,
          '/AutoSelectedBatteryMeasurement': dummy,
          }
        }, self._dbus_value_changed, self._device_added, self._device_removed)

        # Set timezone to user selected timezone
        environ['TZ'] = self._dbusmonitor.get_value(
            'com.victronenergy.settings', '/Settings/System/TimeZone')

        # Connect to localsettings
        self._settings = SettingsDevice(
            bus=self._bus,
            supportedSettings={
                'autostart':
                ['/Settings/Generator0/AutoStartEnabled', 1, 0, 1],
                'accumulateddaily':
                ['/Settings/Generator0/AccumulatedDaily', '', 0, 0],
                'accumulatedtotal':
                ['/Settings/Generator0/AccumulatedTotal', 0, 0, 0],
                'batterymeasurement':
                ['/Settings/Generator0/BatteryService', "default", 0, 0],
                'minimumruntime':
                ['/Settings/Generator0/MinimumRuntime', 0, 0,
                 86400],  # minutes
                # On permanent loss of communication: 0 = Stop, 1 = Start, 2 = keep running
                'onlosscommunication':
                ['/Settings/Generator0/OnLossCommunication', 0, 0, 2],
                # Quiet hours
                'quiethoursenabled':
                ['/Settings/Generator0/QuietHours/Enabled', 0, 0, 1],
                'quiethoursstarttime':
                ['/Settings/Generator0/QuietHours/StartTime', 75600, 0, 86400],
                'quiethoursendtime':
                ['/Settings/Generator0/QuietHours/EndTime', 21600, 0, 86400],
                # SOC
                'socenabled': ['/Settings/Generator0/Soc/Enabled', 0, 0, 1],
                'socstart':
                ['/Settings/Generator0/Soc/StartValue', 90, 0, 100],
                'socstop': ['/Settings/Generator0/Soc/StopValue', 90, 0, 100],
                'qh_socstart':
                ['/Settings/Generator0/Soc/QuietHoursStartValue', 90, 0, 100],
                'qh_socstop':
                ['/Settings/Generator0/Soc/QuietHoursStopValue', 90, 0, 100],
                # Voltage
                'batteryvoltageenabled': [
                    '/Settings/Generator0/BatteryVoltage/Enabled', 0, 0, 1
                ],
                'batteryvoltagestart': [
                    '/Settings/Generator0/BatteryVoltage/StartValue', 11.5, 0,
                    150
                ],
                'batteryvoltagestop': [
                    '/Settings/Generator0/BatteryVoltage/StopValue', 12.4, 0,
                    150
                ],
                'batteryvoltagestarttimer': [
                    '/Settings/Generator0/BatteryVoltage/StartTimer', 20, 0,
                    10000
                ],
                'batteryvoltagestoptimer': [
                    '/Settings/Generator0/BatteryVoltage/StopTimer', 20, 0,
                    10000
                ],
                'qh_batteryvoltagestart': [
                    '/Settings/Generator0/BatteryVoltage/QuietHoursStartValue',
                    11.9, 0, 100
                ],
                'qh_batteryvoltagestop': [
                    '/Settings/Generator0/BatteryVoltage/QuietHoursStopValue',
                    12.4, 0, 100
                ],
                # Current
                'batterycurrentenabled': [
                    '/Settings/Generator0/BatteryCurrent/Enabled', 0, 0, 1
                ],
                'batterycurrentstart': [
                    '/Settings/Generator0/BatteryCurrent/StartValue', 10.5,
                    0.5, 1000
                ],
                'batterycurrentstop': [
                    '/Settings/Generator0/BatteryCurrent/StopValue', 5.5, 0,
                    1000
                ],
                'batterycurrentstarttimer': [
                    '/Settings/Generator0/BatteryCurrent/StartTimer', 20, 0,
                    10000
                ],
                'batterycurrentstoptimer': [
                    '/Settings/Generator0/BatteryCurrent/StopTimer', 20, 0,
                    10000
                ],
                'qh_batterycurrentstart': [
                    '/Settings/Generator0/BatteryCurrent/QuietHoursStartValue',
                    20.5, 0, 1000
                ],
                'qh_batterycurrentstop': [
                    '/Settings/Generator0/BatteryCurrent/QuietHoursStopValue',
                    15.5, 0, 1000
                ],
                # AC load
                'acloadenabled': [
                    '/Settings/Generator0/AcLoad/Enabled', 0, 0, 1
                ],
                'acloadstart': [
                    '/Settings/Generator0/AcLoad/StartValue', 1600, 5, 100000
                ],
                'acloadstop': [
                    '/Settings/Generator0/AcLoad/StopValue', 800, 0, 100000
                ],
                'acloadstarttimer': [
                    '/Settings/Generator0/AcLoad/StartTimer', 20, 0, 10000
                ],
                'acloadstoptimer': [
                    '/Settings/Generator0/AcLoad/StopTimer', 20, 0, 10000
                ],
                'qh_acloadstart': [
                    '/Settings/Generator0/AcLoad/QuietHoursStartValue', 1900,
                    0, 100000
                ],
                'qh_acloadstop': [
                    '/Settings/Generator0/AcLoad/QuietHoursStopValue', 1200, 0,
                    100000
                ],
                # VE.Bus high temperature
                'inverterhightempenabled': [
                    '/Settings/Generator0/InverterHighTemp/Enabled', 0, 0, 1
                ],
                'inverterhightempstarttimer': [
                    '/Settings/Generator0/InverterHighTemp/StartTimer', 20, 0,
                    10000
                ],
                'inverterhightempstoptimer': [
                    '/Settings/Generator0/InverterHighTemp/StopTimer', 20, 0,
                    10000
                ],
                # VE.Bus overload
                'inverteroverloadenabled': [
                    '/Settings/Generator0/InverterOverload/Enabled', 0, 0, 1
                ],
                'inverteroverloadstarttimer': [
                    '/Settings/Generator0/InverterOverload/StartTimer', 20, 0,
                    10000
                ],
                'inverteroverloadstoptimer': [
                    '/Settings/Generator0/InverterOverload/StopTimer', 20, 0,
                    10000
                ],
                # TestRun
                'testrunenabled': [
                    '/Settings/Generator0/TestRun/Enabled', 0, 0, 1
                ],
                'testrunstartdate': [
                    '/Settings/Generator0/TestRun/StartDate',
                    time.time(), 0, 10000000000.1
                ],
                'testrunstarttimer': [
                    '/Settings/Generator0/TestRun/StartTime', 54000, 0, 86400
                ],
                'testruninterval': [
                    '/Settings/Generator0/TestRun/Interval', 28, 1, 365
                ],
                'testrunruntime': [
                    '/Settings/Generator0/TestRun/Duration', 7200, 1, 86400
                ],
                'testrunskipruntime': [
                    '/Settings/Generator0/TestRun/SkipRuntime', 0, 0, 100000
                ],
                'testruntillbatteryfull': [
                    '/Settings/Generator0/TestRun/RunTillBatteryFull', 0, 0, 1
                ]
            },
            eventCallback=self._handle_changed_setting)

        # Whenever services come or go, we need to check if it was a service we use. Note that this
        # is a bit double: DbusMonitor does the same thing. But since we don't use DbusMonitor to
        # monitor for com.victronenergy.battery, .vebus, .charger or any other possible source of
        # battery data, it is necessary to monitor for changes in the available dbus services.
        self._bus.add_signal_receiver(self._dbus_name_owner_changed,
                                      signal_name='NameOwnerChanged')

        self._evaluate_if_we_are_needed()
        gobject.timeout_add(1000, self._handletimertick)
        self._update_relay()
        self._changed = True
def main():
    parser = ArgumentParser(description=sys.argv[0])
    parser.add_argument(
        '--servicebase',
        help='Base service name on dbus, default is com.victronenergy',
        default='com.victronenergy')
    parser.add_argument(
        '--poll',
        help=
        'Use a different kind of polling. Options are epoll, dumb and debug',
        default='epoll')
    parser.add_argument('inputs', nargs='+', help='Path to digital input')
    args = parser.parse_args()

    PulseCounter = {
        'debug': DebugPulseCounter,
        'poll': PollingPulseCounter,
    }.get(args.poll, EpollPulseCounter)

    DBusGMainLoop(set_as_default=True)

    # Keep track of enabled services
    services = {}
    inputs = dict(enumerate(args.inputs, 1))
    pulses = PulseCounter()  # callable that iterates over pulses

    def register_gpio(path, gpio, bus, settings):
        _type = settings['inputtype']
        print("Registering GPIO {} for type {}".format(gpio, _type))

        handler = PinHandler.createHandler(_type, bus, args.servicebase, path,
                                           gpio, settings)
        services[gpio] = handler

        # Only monitor if enabled
        if _type > 0:
            handler.level = pulses.register(path, gpio)
            handler.refresh()

    def unregister_gpio(gpio):
        print("unRegistering GPIO {}".format(gpio))
        pulses.unregister(gpio)
        services[gpio].deactivate()

    def handle_setting_change(inp, setting, old, new):
        if setting == 'inputtype':
            if new:
                # Get current bus and settings objects, to be reused
                service = services[inp]
                bus, settings = service.bus, service.settings

                # Input enabled. If already enabled, unregister the old one first.
                if pulses.registered(inp):
                    unregister_gpio(inp)

                # Before registering the new input, reset its settings to defaults
                settings['count'] = 0
                settings['invert'] = 0
                settings['invertalarm'] = 0
                settings['alarm'] = 0

                # Register it
                register_gpio(inputs[inp], inp, bus, settings)
            elif old:
                # Input disabled
                unregister_gpio(inp)
        elif setting in ('rate', 'invert', 'alarm', 'invertalarm'):
            services[inp].refresh()
        elif setting == 'name':
            services[inp].product_name = new
        elif setting == 'count':
            # Don't want this triggered on a period save, so only execute
            # if it has changed.
            v = int(new)
            s = services[inp]
            if s.count != v:
                s.count = v
                s.refresh()

    for inp, pth in inputs.items():
        supported_settings = {
            'inputtype': [
                '/Settings/DigitalInput/{}/Type'.format(inp), 0, 0,
                len(INPUTTYPES)
            ],
            'rate': [
                '/Settings/DigitalInput/{}/Multiplier'.format(inp), 0.001, 0,
                1.0
            ],
            'count':
            ['/Settings/DigitalInput/{}/Count'.format(inp), 0, 0, MAXCOUNT, 1],
            'invert': [
                '/Settings/DigitalInput/{}/InvertTranslation'.format(inp), 0,
                0, 1
            ],
            'invertalarm':
            ['/Settings/DigitalInput/{}/InvertAlarm'.format(inp), 0, 0, 1],
            'alarm':
            ['/Settings/DigitalInput/{}/AlarmSetting'.format(inp), 0, 0, 1],
            'name':
            ['/Settings/DigitalInput/{}/CustomName'.format(inp), '', '', ''],
        }
        bus = dbusconnection()
        sd = SettingsDevice(bus,
                            supported_settings,
                            partial(handle_setting_change, inp),
                            timeout=10)
        register_gpio(pth, inp, bus, sd)

    def poll(mainloop):
        from time import time
        idx = 0

        try:
            for inp, level in pulses():
                # epoll object only resyncs once a second. We may receive
                # a pulse for something that's been deregistered.
                try:
                    services[inp].toggle(level)
                except KeyError:
                    continue
        except:
            traceback.print_exc()
            mainloop.quit()

    # Need to run the gpio polling in separate thread. Pass in the mainloop so
    # the thread can kill us if there is an exception.
    mainloop = GLib.MainLoop()

    poller = Thread(target=lambda: poll(mainloop))
    poller.daemon = True
    poller.start()

    # Periodically save the counter
    def save_counters():
        for inp in inputs:
            services[inp].save_count()
        return True

    GLib.timeout_add(SAVEINTERVAL, save_counters)

    # Save counter on shutdown
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))

    try:
        mainloop.run()
    except KeyboardInterrupt:
        pass
    finally:
        save_counters()
	def _create_settings(self, *args, **kwargs):
		bus = dbus.SessionBus() if 'DBUS_SESSION_BUS_ADDRESS' in os.environ else dbus.SystemBus()
		return SettingsDevice(bus, *args, timeout=10, **kwargs)
Esempio n. 11
0
    def __init__(self,
                 servicename,
                 deviceinstance,
                 voltage,
                 capacity,
                 productname='Valence U-BMS',
                 connection='can0'):
        self.minUpdateDone = 0
        self.dailyResetDone = 0

        self._bat = UbmsBattery(capacity=capacity,
                                voltage=voltage,
                                connection=connection)

        self._dbusservice = VeDbusService(servicename + '.socketcan_' +
                                          connection + '_di' +
                                          str(deviceinstance))

        logging.debug("%s /DeviceInstance = %d" %
                      (servicename + '.socketcan_' + connection + '_di' +
                       str(deviceinstance), deviceinstance))

        # Create the management objects, as specified in the ccgx dbus-api document
        self._dbusservice.add_path('/Mgmt/ProcessName', __file__)
        self._dbusservice.add_path(
            '/Mgmt/ProcessVersion',
            VERSION + ' running on Python ' + platform.python_version())
        self._dbusservice.add_path('/Mgmt/Connection', connection)

        # Create the mandatory objects
        self._dbusservice.add_path('/DeviceInstance', deviceinstance)
        self._dbusservice.add_path('/ProductId', 0)
        self._dbusservice.add_path('/ProductName', productname)
        self._dbusservice.add_path('/FirmwareVersion', 'unknown')
        self._dbusservice.add_path('/HardwareVersion', 'unknown')
        self._dbusservice.add_path('/Connected', 0)
        # Create battery specific objects
        self._dbusservice.add_path('/Status', 0)
        self._dbusservice.add_path('/Mode',
                                   1,
                                   writeable=True,
                                   onchangecallback=self._transmit_mode)
        self._dbusservice.add_path('/Soh', 100)
        self._dbusservice.add_path('/Capacity', int(capacity))
        self._dbusservice.add_path('/InstalledCapacity', int(capacity))
        self._dbusservice.add_path('/Dc/0/Temperature', 25)
        self._dbusservice.add_path('/Info/MaxChargeCurrent', 70)
        self._dbusservice.add_path('/Info/MaxDischargeCurrent', 150)
        self._dbusservice.add_path('/Info/MaxChargeVoltage', float(voltage))
        self._dbusservice.add_path('/Info/BatteryLowVoltage', 24.0)
        self._dbusservice.add_path('/Alarms/CellImbalance', 0)
        self._dbusservice.add_path('/Alarms/LowVoltage', 0)
        self._dbusservice.add_path('/Alarms/HighVoltage', 0)
        self._dbusservice.add_path('/Alarms/HighDischargeCurrent', 0)
        self._dbusservice.add_path('/Alarms/HighChargeCurrent', 0)
        self._dbusservice.add_path('/Alarms/LowSoc', 0)
        self._dbusservice.add_path('/Alarms/LowTemperature', 0)
        self._dbusservice.add_path('/Alarms/HighTemperature', 0)
        self._dbusservice.add_path('/Balancing', 0)
        self._dbusservice.add_path('/System/HasTemperature', 1)
        self._dbusservice.add_path('/System/NrOfBatteries', 10)
        self._dbusservice.add_path('/System/NrOfModulesOnline', 10)
        self._dbusservice.add_path('/System/NrOfModulesOffline', 0)
        self._dbusservice.add_path('/System/NrOfModulesBlockingDischarge', 0)
        self._dbusservice.add_path('/System/NrOfModulesBlockingCharge', 0)
        self._dbusservice.add_path('/System/NrOfBatteriesBalancing', 0)
        self._dbusservice.add_path('/System/BatteriesParallel', 5)
        self._dbusservice.add_path('/System/BatteriesSeries', 2)
        self._dbusservice.add_path('/System/NrOfCellsPerBattery', 4)
        self._dbusservice.add_path('/System/MinVoltageCellId', 'M_C_')
        self._dbusservice.add_path('/System/MaxVoltageCellId', 'M_C_')
        self._dbusservice.add_path('/System/MinCellTemperature', 10.0)
        self._dbusservice.add_path('/System/MaxCellTemperature', 10.0)
        self._dbusservice.add_path('/System/MaxPcbTemperature', 10.0)

        self._settings = SettingsDevice(
            bus=dbus.SystemBus() if
            (platform.machine() == 'armv7l') else dbus.SessionBus(),
            supportedSettings={
                'AvgDischarge':
                ['/Settings/Ubms/AvgerageDischarge', 0.0, 0, 0],
                'TotalAhDrawn': ['/Settings/Ubms/TotalAhDrawn', 0.0, 0, 0],
                'TimeLastFull': ['/Settings/Ubms/TimeLastFull', 0.0, 0, 0],
                'MinCellVoltage':
                ['/Settings/Ubms/MinCellVoltage', 4.0, 2.0, 4.0],
                'MaxCellVoltage':
                ['/Settings/Ubms/MaxCellVoltage', 2.0, 2.0, 4.0],
                'interval': ['/Settings/Ubms/Interval', 50, 50, 200]
            },
            eventCallback=handle_changed_setting)

        self._summeditems = {
            '/System/MaxCellVoltage': {
                'gettext': '%.2F V'
            },
            '/System/MinCellVoltage': {
                'gettext': '%.2F V'
            },
            '/Dc/0/Voltage': {
                'gettext': '%.2F V'
            },
            '/Dc/0/Current': {
                'gettext': '%.1F A'
            },
            '/Dc/0/Power': {
                'gettext': '%.0F W'
            },
            '/Soc': {
                'gettext': '%.0F %%'
            },
            '/History/TotalAhDrawn': {
                'gettext': '%.0F Ah'
            },
            '/History/DischargedEnergy': {
                'gettext': '%.2F kWh'
            },
            '/History/ChargedEnergy': {
                'gettext': '%.2F kWh'
            },
            '/History/AverageDischarge': {
                'gettext': '%.2F kWh'
            },
            '/TimeToGo': {
                'gettext': '%.0F s'
            },
            '/ConsumedAmphours': {
                'gettext': '%.1F Ah'
            }
        }
        for path in self._summeditems.keys():
            self._dbusservice.add_path(path,
                                       value=None,
                                       gettextcallback=self._gettext)

        self._dbusservice['/History/AverageDischarge'] = self._settings[
            'AvgDischarge']
        self._dbusservice['/History/TotalAhDrawn'] = self._settings[
            'TotalAhDrawn']
        self._dbusservice.add_path('/History/TimeSinceLastFullCharge', 0)
        self._dbusservice.add_path('/History/MinCellVoltage',
                                   self._settings['MinCellVoltage'])
        self._dbusservice.add_path('/History/MaxCellVoltage',
                                   self._settings['MaxCellVoltage'])
        self._dbusservice['/ConsumedAmphours'] = 0

        logging.info(
            "History cell voltage min: %.3f, max: %.3f, totalAhDrawn: %d",
            self._settings['MinCellVoltage'], self._settings['MaxCellVoltage'],
            self._settings['TotalAhDrawn'])

        self._dbusservice['/History/ChargedEnergy'] = 0
        self._dbusservice['/History/DischargedEnergy'] = 0

        gobject.timeout_add(self._settings['interval'], exit_on_error,
                            self._update)
Esempio n. 12
0
    def __init__(self,
                 dbusmonitor_gen=None,
                 dbusservice_gen=None,
                 settings_device_gen=None):
        self.STATE_IDLE = 0
        self.STATE_CHARGING = 1
        self.STATE_DISCHARGING = 2

        self.BATSERVICE_DEFAULT = 'default'
        self.BATSERVICE_NOBATTERY = 'nobattery'

        # Why this dummy? Because DbusMonitor expects these values to be there, even though we don't
        # need them. So just add some dummy data. This can go away when DbusMonitor is more generic.
        dummy = {
            'code': None,
            'whenToLog': 'configChange',
            'accessLevel': None
        }
        dbus_tree = {
            'com.victronenergy.solarcharger': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/Dc/0/Voltage': dummy,
                '/Dc/0/Current': dummy
            },
            'com.victronenergy.pvinverter': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/Ac/L1/Power': dummy,
                '/Ac/L2/Power': dummy,
                '/Ac/L3/Power': dummy,
                '/Position': dummy,
                '/ProductId': dummy
            },
            'com.victronenergy.battery': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/Dc/0/Voltage': dummy,
                '/Dc/0/Current': dummy,
                '/Dc/0/Power': dummy,
                '/Soc': dummy,
                '/TimeToGo': dummy,
                '/ConsumedAmphours': dummy,
                '/ProductId': dummy
            },
            'com.victronenergy.vebus': {
                '/Ac/ActiveIn/ActiveInput': dummy,
                '/Ac/ActiveIn/L1/P': dummy,
                '/Ac/ActiveIn/L2/P': dummy,
                '/Ac/ActiveIn/L3/P': dummy,
                '/Ac/Out/L1/P': dummy,
                '/Ac/Out/L2/P': dummy,
                '/Ac/Out/L3/P': dummy,
                '/Connected': dummy,
                '/Hub4/AcPowerSetpoint': dummy,
                '/ProductId': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/Mode': dummy,
                '/State': dummy,
                '/Dc/0/Voltage': dummy,
                '/Dc/0/Current': dummy,
                '/Dc/0/Power': dummy,
                '/Soc': dummy
            },
            'com.victronenergy.charger': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/Dc/0/Voltage': dummy,
                '/Dc/0/Current': dummy
            },
            'com.victronenergy.grid': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/ProductId': dummy,
                '/DeviceType': dummy,
                '/Ac/L1/Power': dummy,
                '/Ac/L2/Power': dummy,
                '/Ac/L3/Power': dummy
            },
            'com.victronenergy.genset': {
                '/Connected': dummy,
                '/ProductName': dummy,
                '/Mgmt/Connection': dummy,
                '/ProductId': dummy,
                '/DeviceType': dummy,
                '/Ac/L1/Power': dummy,
                '/Ac/L2/Power': dummy,
                '/Ac/L3/Power': dummy
            },
            'com.victronenergy.settings': {
                '/Settings/SystemSetup/AcInput1': dummy,
                '/Settings/SystemSetup/AcInput2': dummy
            }
        }

        if dbusmonitor_gen is None:
            self._dbusmonitor = DbusMonitor(dbus_tree,
                                            self._dbus_value_changed,
                                            self._device_added,
                                            self._device_removed)
        else:
            self._dbusmonitor = dbusmonitor_gen(dbus_tree)

        # Connect to localsettings
        supported_settings = {
            'batteryservice': [
                '/Settings/SystemSetup/BatteryService',
                self.BATSERVICE_DEFAULT, 0, 0
            ],
            'hasdcsystem': ['/Settings/SystemSetup/HasDcSystem', 0, 0, 1],
            'writevebussoc': ['/Settings/SystemSetup/WriteVebusSoc', 0, 0, 1]
        }

        if settings_device_gen is None:
            self._settings = SettingsDevice(
                bus=dbus.SessionBus() if 'DBUS_SESSION_BUS_ADDRESS'
                in os.environ else dbus.SystemBus(),
                supportedSettings=supported_settings,
                eventCallback=self._handlechangedsetting)
        else:
            self._settings = settings_device_gen(supported_settings,
                                                 self._handlechangedsetting)

        # put ourselves on the dbus
        if dbusservice_gen is None:
            self._dbusservice = VeDbusService('com.victronenergy.system')
        else:
            self._dbusservice = dbusservice_gen('com.victronenergy.system')

        self._dbusservice.add_mandatory_paths(
            processname=__file__,
            processversion=softwareVersion,
            connection='data from other dbus processes',
            deviceinstance=0,
            productid=None,
            productname=None,
            firmwareversion=None,
            hardwareversion=None,
            connected=1)

        # At this moment, VRM portal ID is the MAC address of the CCGX. Anyhow, it should be string uniquely
        # identifying the CCGX.
        self._dbusservice.add_path('/Serial',
                                   value=get_vrm_portal_id(),
                                   gettextcallback=lambda x: str(x))
        self._dbusservice.add_path('/Relay/0/State',
                                   value=None,
                                   writeable=True,
                                   onchangecallback=lambda p, v: exit_on_error(
                                       self._on_relay_state_changed, p, v))

        self._dbusservice.add_path('/AvailableBatteryServices',
                                   value=None,
                                   gettextcallback=self._gettext)
        self._dbusservice.add_path('/AvailableBatteryMeasurements', value=None)
        self._dbusservice.add_path('/AutoSelectedBatteryService',
                                   value=None,
                                   gettextcallback=self._gettext)
        self._dbusservice.add_path('/AutoSelectedBatteryMeasurement',
                                   value=None,
                                   gettextcallback=self._gettext)
        self._dbusservice.add_path('/ActiveBatteryService',
                                   value=None,
                                   gettextcallback=self._gettext)
        self._dbusservice.add_path('/PvInvertersProductIds', value=None)
        self._dbusservice.add_path('/Dc/Battery/Alarms/CircuitBreakerTripped',
                                   value=None)
        self._summeditems = {
            '/Ac/Grid/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Grid/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Grid/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Grid/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Grid/NumberOfPhases': {
                'gettext': '%.0F W'
            },
            '/Ac/Grid/ProductId': {
                'gettext': '%s'
            },
            '/Ac/Grid/DeviceType': {
                'gettext': '%s'
            },
            '/Ac/Genset/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Genset/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Genset/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Genset/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Genset/NumberOfPhases': {
                'gettext': '%.0F W'
            },
            '/Ac/Genset/ProductId': {
                'gettext': '%s'
            },
            '/Ac/Genset/DeviceType': {
                'gettext': '%s'
            },
            '/Ac/Consumption/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Consumption/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Consumption/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Consumption/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/Consumption/NumberOfPhases': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnOutput/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnOutput/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnOutput/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnOutput/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnOutput/NumberOfPhases': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGrid/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGrid/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGrid/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGrid/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGrid/NumberOfPhases': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGenset/L1/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGenset/L2/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGenset/L3/Power': {
                'gettext': '%.0F W'
            },
            '/Ac/PvOnGenset/NumberOfPhases': {
                'gettext': '%d'
            },
            '/Ac/PvOnGenset/Total/Power': {
                'gettext': '%.0F W'
            },
            '/Dc/Pv/Power': {
                'gettext': '%.0F W'
            },
            '/Dc/Pv/Current': {
                'gettext': '%.1F A'
            },
            '/Dc/Battery/Voltage': {
                'gettext': '%.2F V'
            },
            '/Dc/Battery/Current': {
                'gettext': '%.1F A'
            },
            '/Dc/Battery/Power': {
                'gettext': '%.0F W'
            },
            '/Dc/Battery/Soc': {
                'gettext': '%.0F %%'
            },
            '/Dc/Battery/State': {
                'gettext': '%s'
            },
            '/Dc/Battery/TimeToGo': {
                'gettext': '%.0F s'
            },
            '/Dc/Battery/ConsumedAmphours': {
                'gettext': '%.1F Ah'
            },
            '/Dc/Charger/Power': {
                'gettext': '%.0F %%'
            },
            '/Dc/Vebus/Current': {
                'gettext': '%.1F A'
            },
            '/Dc/Vebus/Power': {
                'gettext': '%.0F W'
            },
            '/Dc/System/Power': {
                'gettext': '%.0F W'
            },
            '/Hub': {
                'gettext': '%s'
            },
            '/Ac/ActiveIn/Source': {
                'gettext': '%s'
            },
            '/VebusService': {
                'gettext': '%s'
            }
        }

        for path in self._summeditems.keys():
            self._dbusservice.add_path(path,
                                       value=None,
                                       gettextcallback=self._gettext)

        self._batteryservice = None
        self._determinebatteryservice()

        self._supervised = {}
        self._lg_battery = None

        if self._batteryservice is None:
            logger.info("Battery service initialized to None (setting == %s)" %
                        self._settings['batteryservice'])

        self._changed = True
        for service, instance in self._dbusmonitor.get_service_list().items():
            self._device_added(service, instance, do_service_change=False)

        self._handleservicechange()
        self._updatevalues()
        try:
            self._relay_file_read = open(relayGpioFile, 'rt')
            self._relay_file_write = open(relayGpioFile, 'wt')
            self._update_relay_state()
            gobject.timeout_add(5000, exit_on_error, self._update_relay_state)
        except IOError:
            self._relay_file_read = None
            self._relay_file_write = None
            logging.warn('Could not open %s (relay)' % relayGpioFile)

        self._writeVebusSocCounter = 9
        gobject.timeout_add(1000, exit_on_error, self._handletimertick)
        gobject.timeout_add(60000, exit_on_error, self._process_supervised)
Esempio n. 13
0
def main():
    parser = ArgumentParser(description=sys.argv[0])
    parser.add_argument('inputs', nargs='+', help='Path to digital input')
    args = parser.parse_args()

    DBusGMainLoop(set_as_default=True)
    dbusservice = VeDbusService('com.victronenergy.digitalinput')

    inputs = dict(enumerate(args.inputs, 1))
    pulses = EpollPulseCounter()  # callable that iterates over pulses

    def register_gpio(path, gpio, f):
        print "Registering GPIO {} for function {}".format(gpio, f)
        dbusservice.add_path('/Count/{}'.format(gpio), value=0)
        dbusservice['/Count/{}'.format(gpio)] = settings[gpio]['count']
        if f == INPUT_FUNCTION_COUNTER:
            dbusservice.add_path('/Volume/{}'.format(gpio), value=0)
            dbusservice['/Volume/{}'.format(
                gpio)] = settings[gpio]['count'] * settings[gpio]['rate']
        elif f == INPUT_FUNCTION_ALARM:
            dbusservice.add_path('/Alarms/{}'.format(gpio), value=0)
        pulses.register(path, gpio)

    def unregister_gpio(gpio):
        print "unRegistering GPIO {}".format(gpio)
        pulses.unregister(gpio)
        for pth in ('Count', 'Volume', 'Alarms'):
            k = '/{}/{}'.format(pth, gpio)
            if k in dbusservice:
                del dbusservice[k]

    # Interface to settings
    def handle_setting_change(inp, setting, old, new):
        if setting == 'function':
            if new:
                # Input enabled. If already enabled, unregister the old one first.
                if pulses.registered(inp):
                    unregister_gpio(inp)
                register_gpio(inputs[inp], inp, int(new))
            elif old:
                # Input disabled
                unregister_gpio(inp)

    settings = {}
    for inp, pth in inputs.items():
        supported_settings = {
            'function':
            ['/Settings/DigitalInput/{}/Function'.format(inp), 0, 0, 2],
            'rate': [
                '/Settings/DigitalInput/{}/LitersPerPulse'.format(inp), 1, 1,
                100
            ],
            'count':
            ['/Settings/DigitalInput/{}/Count'.format(inp), 0, 0, MAXCOUNT, 1]
        }
        settings[inp] = sd = SettingsDevice(dbusservice.dbusconn,
                                            supported_settings,
                                            partial(handle_setting_change,
                                                    inp),
                                            timeout=10)
        if sd['function'] > 0:
            register_gpio(pth, inp, int(sd['function']))

    def poll(mainloop):
        from time import time
        #stamps = { inp: [0] * 5 for inp in gpios }
        idx = 0

        try:
            for inp, level in pulses():
                function = settings[inp]['function']

                # Only increment Count on rising edge.
                if level:
                    countpath = '/Count/{}'.format(inp)
                    v = (dbusservice[countpath] + 1) % MAXCOUNT
                    dbusservice[countpath] = v
                    if function == INPUT_FUNCTION_COUNTER:
                        dbusservice['/Volume/{}'.format(
                            inp)] = v * settings[inp]['rate']

                if function == INPUT_FUNCTION_ALARM:
                    dbusservice['/Alarms/{}'.format(inp)] = bool(
                        level) * 2  # Nasty way of limiting to 0 or 2.
        except:
            traceback.print_exc()
            mainloop.quit()

    # Need to run the gpio polling in separate thread. Pass in the mainloop so
    # the thread can kill us if there is an exception.
    gobject.threads_init()
    mainloop = gobject.MainLoop()

    poller = Thread(target=lambda: poll(mainloop))
    poller.daemon = True
    poller.start()

    # Periodically save the counter
    def _save_counters():
        for inp in inputs:
            if settings[inp]['function'] > 0:
                settings[inp]['count'] = dbusservice['/Count/{}'.format(inp)]

    def save_counters():
        _save_counters()
        gobject.timeout_add(SAVEINTERVAL, save_counters)

    gobject.timeout_add(SAVEINTERVAL, save_counters)

    # Save counter on shutdown
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))

    try:
        mainloop.run()
    except KeyboardInterrupt:
        pass
    finally:
        _save_counters()
Esempio n. 14
0
    def __init__(self):
        self.RELAY_GPIO_FILE = '/sys/class/gpio/gpio182/value'
        self.SERVICE_NOBATTERY = 'nobattery'
        self.SERVICE_NOVEBUS = 'novebus'
        self.HISTORY_DAYS = 30
        self._last_counters_check = 0
        self._dbusservice = None
        self._batteryservice = None
        self._vebusservice = None
        self._starttime = 0
        self._manualstarttimer = 0
        self._last_runtime_update = 0
        self.timer_runnning = 0

        self._condition_stack = {
            'batteryvoltage': {
                'name': 'batteryvoltage',
                'reached': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False
            },
            'batterycurrent': {
                'name': 'batterycurrent',
                'reached': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False
            },
            'acload': {
                'name': 'acload',
                'reached': False,
                'timed': True,
                'start_timer': 0,
                'stop_timer': 0,
                'valid': True,
                'enabled': False
            },
            'soc': {
                'name': 'soc',
                'reached': False,
                'timed': False,
                'valid': True,
                'enabled': False
            }
        }

        # DbusMonitor expects these values to be there, even though we don need them. So just
        # add some dummy data. This can go away when DbusMonitor is more generic.
        dummy = {
            'code': None,
            'whenToLog': 'configChange',
            'accessLevel': None
        }

        self._dbusmonitor = DbusMonitor(
            {
                'com.victronenergy.vebus': {
                    '/Connected': dummy,
                    '/ProductName': dummy,
                    '/Mgmt/Connection': dummy,
                    '/State': dummy,
                    '/Ac/Out/P': dummy,
                    '/Dc/I': dummy,
                    '/Dc/V': dummy,
                    '/Soc': dummy
                },
                'com.victronenergy.battery': {
                    '/Connected': dummy,
                    '/ProductName': dummy,
                    '/Mgmt/Connection': dummy,
                    '/Dc/0/V': dummy,
                    '/Dc/0/I': dummy,
                    '/Dc/0/P': dummy,
                    '/Soc': dummy
                },
                'com.victronenergy.settings':
                {  # This is not our setting so do it here. not in supportedSettings
                    '/Settings/Relay/Function': dummy,
                    '/Settings/Relay/Polarity': dummy,
                    '/Settings/System/TimeZone': dummy
                }
            },
            self._dbus_value_changed,
            self._device_added,
            self._device_removed)

        # Set timezone to user selected timezone
        environ['TZ'] = self._dbusmonitor.get_value(
            'com.victronenergy.settings', '/Settings/System/TimeZone')

        # Connect to localsettings
        self._settings = SettingsDevice(
            bus=dbus.SystemBus() if
            (platform.machine() == 'armv7l') else dbus.SessionBus(),
            supportedSettings={
                'autostart': ['/Settings/Generator/AutoStart', 0, 0, 1],
                'accumulateddaily':
                ['/Settings/Generator/AccumulatedDaily', '', 0, 0],
                'accumulatedtotal':
                ['/Settings/Generator/AccumulatedTotal', 0, 0, 0],
                'batteryservice': [
                    '/Settings/Generator/BatteryService',
                    self.SERVICE_NOBATTERY, 0, 0
                ],
                'vebusservice': [
                    '/Settings/Generator/VebusService', self.SERVICE_NOVEBUS,
                    0, 0
                ],
                # Silent mode
                'silentmodeenabled':
                ['/Settings/Generator/SilentMode/Enabled', 0, 0, 1],
                'silentmodestarttimer':
                ['/Settings/Generator/SilentMode/StartTime', 0, 0, 86400],
                'silentmodeendtime':
                ['/Settings/Generator/SilentMode/EndTime', 0, 0, 86400],
                # SOC
                'socenabled': ['/Settings/Generator/Soc/Enabled', 0, 0, 1],
                'socstart': ['/Settings/Generator/Soc/StartValue', 90, 0, 100],
                'socstop': ['/Settings/Generator/Soc/StopValue', 90, 0, 100],
                'em_socstart':
                ['/Settings/Generator/Soc/EmergencyStartValue', 90, 0, 100],
                'em_socstop':
                ['/Settings/Generator/Soc/EmergencyStopValue', 90, 0, 100],
                # Voltage
                'batteryvoltageenabled':
                ['/Settings/Generator/BatteryVoltage/Enabled', 0, 0, 1],
                'batteryvoltagestart': [
                    '/Settings/Generator/BatteryVoltage/StartValue', 11.5, 0,
                    150
                ],
                'batteryvoltagestop':
                ['/Settings/Generator/BatteryVoltage/StopValue', 12.4, 0, 150],
                'batteryvoltagestarttimer': [
                    '/Settings/Generator/BatteryVoltage/StartTimer', 20, 0,
                    10000
                ],
                'batteryvoltagestoptimer':
                ['/Settings/Generator/BatteryVoltage/StopTimer', 20, 0, 10000],
                'em_batteryvoltagestart': [
                    '/Settings/Generator/BatteryVoltage/EmergencyStartValue',
                    11.9, 0, 100
                ],
                'em_batteryvoltagestop': [
                    '/Settings/Generator/BatteryVoltage/EmergencyStopValue',
                    12.4, 0, 100
                ],
                # Current
                'batterycurrentenabled':
                ['/Settings/Generator/BatteryCurrent/Enabled', 0, 0, 1],
                'batterycurrentstart': [
                    '/Settings/Generator/BatteryCurrent/StartValue', 10.5, 0.5,
                    1000
                ],
                'batterycurrentstop':
                ['/Settings/Generator/BatteryCurrent/StopValue', 5.5, 0, 1000],
                'batterycurrentstarttimer': [
                    '/Settings/Generator/BatteryCurrent/StartTimer', 20, 0,
                    10000
                ],
                'batterycurrentstoptimer':
                ['/Settings/Generator/BatteryCurrent/StopTimer', 20, 0, 10000],
                'em_batterycurrentstart': [
                    '/Settings/Generator/BatteryCurrent/EmergencyStartValue',
                    20.5, 0, 1000
                ],
                'em_batterycurrentstop': [
                    '/Settings/Generator/BatteryCurrent/EmergencyStopValue',
                    15.5, 0, 1000
                ],
                # AC load
                'acloadenabled': [
                    '/Settings/Generator/AcLoad/Enabled', 0, 0, 1
                ],
                'acloadstart': [
                    '/Settings/Generator/AcLoad/StartValue', 1600, 5, 100000
                ],
                'acloadstop': [
                    '/Settings/Generator/AcLoad/StopValue', 800, 0, 100000
                ],
                'acloadstarttimer': [
                    '/Settings/Generator/AcLoad/StartTimer', 20, 0, 10000
                ],
                'acloadstoptimer': [
                    '/Settings/Generator/AcLoad/StopTimer', 20, 0, 10000
                ],
                'em_acloadstart': [
                    '/Settings/Generator/AcLoad/EmergencyStartValue', 1900, 0,
                    100000
                ],
                'em_acloadstop': [
                    '/Settings/Generator/AcLoad/EmergencyStopValue', 1200, 0,
                    100000
                ],
                # Maintenance
                'maintenanceenabled': [
                    '/Settings/Generator/Maintenance/Enabled', 0, 0, 1
                ],
                'maintenancestartdate': [
                    '/Settings/Generator/Maintenance/StartDate',
                    time.time(), 0, 10000000000.1
                ],
                'maintenancestarttimer':
                ['/Settings/Generator/Maintenance/StartTime', 54000, 0, 86400],
                'maintenanceinterval': [
                    '/Settings/Generator/Maintenance/Interval', 28, 1, 365
                ],
                'maintenanceruntime': [
                    '/Settings/Generator/Maintenance/Duration', 7200, 1, 86400
                ],
                'maintenanceskipruntime': [
                    '/Settings/Generator/Maintenance/SkipRuntime', 0, 0, 100000
                ]
            },
            eventCallback=self._handle_changed_setting)

        self._evaluate_if_we_are_needed()
        gobject.timeout_add(1000, self._handletimertick)
        self._changed = True