Exemple #1
0
 def test_dataUpdate_global(self):
    """Listener can announce catch-all wildcard"""
    testdata = { '/some/path': 1, '/another/path/x': 2 }
    Scheduler().registerData(['*'], self.listener1)
    Scheduler.simulated = True
    Scheduler().dataUpdate(DataPackage(Listener, testdata))
    Scheduler().dataRunner.join()
    self.assertDictEqual(testdata, self.listener1.data[0])
    def test_dummySpeicher(self):
        OpenWBconfig('resources/test.conf')
        data = openWBValues()
        module = SpeicherModule()
        self.assertEqual(2, len(module.modules))
        self.assertEqual(1,
                         data.get('housebattery/boolHouseBatteryConfigured'),
                         'Speicher enabled')

        BAT1, BAT2 = module.modules
        BAT1.P = 1000
        BAT2.P = 2000
        BAT1.soc = 25
        BAT2.soc = 75
        Scheduler().test_callAll()

        self.assertEqual(BAT1.P, data.get('housebattery/1/W'),
                         "BAT1 power has been reported")
        self.assertEqual(BAT2.P, data.get('housebattery/2/W'),
                         "BAT2 power has been reported")
        self.assertEqual(BAT1.P + BAT2.P, data.get('housebattery/W'),
                         "sum power has been reported")
        self.assertEqual(50, data.get('housebattery/%Soc'),
                         "sum SOC has been reported")

        Scheduler().test_callAll()
        BAT1.kwhOut = 5
        BAT2.kwhOut = 10
        BAT1.kwhIn = 15
        BAT2.kwhIn = 20
        Scheduler().test_callAll()

        self.assertEqual(BAT1.kwhIn + BAT2.kwhIn,
                         data.get('housebattery/WhImported'),
                         "EVU energy imported has been reported")
        self.assertEqual(BAT1.kwhOut + BAT2.kwhOut,
                         data.get('housebattery/WhExported'),
                         "EVU energy exported has been reported")

        self.assertEqual(BAT1.kwhIn, data.get('housebattery/1/dailykwhIn'),
                         "BAT1 consumption has been reported (Daily)")
        self.assertEqual(BAT1.kwhOut, data.get('housebattery/1/monthlykwhOut'),
                         "BAT1 generation has been reported (Monthly)")
        self.assertEqual(BAT1.kwhIn + BAT2.kwhIn,
                         data.get('housebattery/DailyYieldImportKwh'),
                         "Sum consumption has been reported (Daily)")
        self.assertEqual(BAT1.kwhOut + BAT2.kwhOut,
                         data.get('housebattery/MonthlyYieldExportKwh'),
                         "Sum generation has been reported (Monthly)")

        Scheduler().signalEvent(OpenWBEvent(EventType.resetDaily))
        BAT1.kwhOut += 10
        BAT2.kwhIn += 20
        Scheduler().test_callAll()
        self.assertEqual(10, data.get('housebattery/MonthlyYieldExportKwh'),
                         "Sum generation daily is offsetted")
        self.assertEqual(20, data.get('housebattery/DailyYieldImportKwh'),
                         "Sum consumption daily is offsetted")
Exemple #3
0
 def setup(self, config):
    self.P  = 0
    self.soc = 0
    self.kwhOut = 0
    self.kwhIn = 0
    self.dailyOffsetOut = 0
    self.dailyOffsetIn = 0
    Scheduler().registerTimer(1, self.loop)
    Scheduler().registerEvent(EventType.resetDaily, self.daily)
Exemple #4
0
 def test_eventListener(self):
    self.daily = False
    self.monthly = False
    def dailyReset(event):
       self.daily = True
    def monthlyReset(event):
       self.monthly = True
    Scheduler().registerEvent(EventType.resetDaily, dailyReset)
    Scheduler().registerEvent(EventType.resetMonthly, monthlyReset)
    Scheduler().signalEvent(OpenWBEvent(EventType.resetDaily, info="Info"))
    self.assertTrue(self.daily)
    self.assertFalse(self.monthly)
Exemple #5
0
    def test_charging(self):
        """Erkenne Ladezustand"""
        OpenWBconfig('resources/test.conf')
        data = openWBValues()
        module = LPModule()
        LP1 = module.modules[0]
        LP1.actP = 200
        Scheduler().test_callAll()
        self.assertFalse(data.get('lp/1/boolChargeStat'),
                         "Fahrzeug lädt nicht")

        LP1.actP = 500
        Scheduler().test_callAll()
        self.assertTrue(data.get('lp/1/boolChargeStat'), "Fahrzeug lädt")
Exemple #6
0
 def setUp(self):
     RamdiskValues._inst = FakeRamdisk()
     if '_inst' in vars(OpenWBconfig):
         del OpenWBconfig._inst
     if '_inst' in vars(Scheduler):
         del Scheduler._inst
     Scheduler(simulated=True)
Exemple #7
0
 def test_dataUpdate_1listener(self):
    Scheduler().registerData(['/some/path/*', '/another/path/*'], self.listener1)
    Scheduler().dataUpdate(DataPackage(Listener, {
       '/some/other/path': 1,
       '/some/path/a': 2}))
    Scheduler().dataUpdate(DataPackage(Listener, {
       '/some/path/subpath/b': 3,
       '/another/path/c': 4
    }))
    Scheduler.simulated = True
    Scheduler().dataRunner.join()
    self.assertEqual(1, len(self.listener1.data), "Listener 1 has received one package")
    self.assertDictEqual({
       '/some/path/a': 2,
       '/some/path/subpath/b': 3,
       '/another/path/c': 4
    }, self.listener1.data[0], "Listener shall have received the registered data branches")
Exemple #8
0
 def setup(self, config):
     self.ip = config.get(self.configprefix + '_ip')
     self.timeout = config.get(self.configprefix + '_timeout', 2)
     self.laststate = {}
     self.setter = GO_E_SET('http://%s/mqtt' % self.ip, self.timeout, self)
     self.setter.start()
     Scheduler().registerTimer(5, self.loop)
     super().setup(config)
Exemple #9
0
 def setup(self, config):
    self.ip = config.get(self.configprefix + '_ip')
    self.swname = config.get(self.configprefix + '_name')
    self.power = config.get(self.configprefix + '_power', 2000)
    self.blockcnt = 0
    self.on_delay = 0
    self.setP = 0
    Scheduler().registerTimer(10, self.loop)
    super().setup(config)
Exemple #10
0
 def setup(self, config):
     self.P = 0
     self.kwhOut = 0
     self.kwhIn = 0
     self.offsetPV = config.get('offsetpv')
     # Weitere Attribute:
     # A1..A3
     # V1..V3
     Scheduler().registerTimer(1, self.loop)
Exemple #11
0
    def test_plugged(self):
        """Erkenne Plugged Status"""
        OpenWBconfig('resources/test.conf')
        data = openWBValues()
        module = LPModule()
        LP1 = module.modules[0]
        LP1.A = 6
        LP1.A1 = 1
        Scheduler().test_callAll(2)
        self.assertFalse(data.get('lp/1/boolPlugStat'),
                         "Fahrzeug nicht eingesteckt")

        LP1.A1 = 5.2
        Scheduler().test_callAll(2)
        self.assertTrue(data.get('lp/1/boolPlugStat'), "Fahrzeug eingesteckt")

        LP1.A1 = 4.9
        Scheduler().test_callAll(2)
        self.assertFalse(data.get('lp/1/boolPlugStat'),
                         "Fahrzeug nicht eingesteckt")
Exemple #12
0
 def setup(self, config) -> None:
     self.ip = config.get(self.configprefix + '_ip')
     self.device = ModbusDevice(self.ip)
     if config.get(self.configprefix + '_bms') == "batrium":
         from .bms_batrium import BATRIUM
         self.bms = BATRIUM(1)
         self.bms.setup(self)
         self.bms.start()
     else:
         self.bms = None
     super().setup(config)
     Scheduler().registerTimer(10, self.loop)
Exemple #13
0
    def test_phasecount(self):
        """Zähle angeschlossene Phasen"""
        OpenWBconfig('resources/test.conf')
        data = openWBValues()
        module = LPModule()
        LP1 = module.modules[0]
        LP1.A = 6
        LP1.A1 = 1
        Scheduler().test_callAll()
        LP1.zaehle_phasen()
        Scheduler().test_callAll()
        self.assertEqual(1, data.get('lp/1/countPhasesInUse'),
                         "1 Phase wird erkannt")

        LP1.A2 = 1
        Scheduler().test_callAll()
        LP1.zaehle_phasen()
        Scheduler().test_callAll()
        self.assertEqual(1, data.get('lp/1/countPhasesInUse'),
                         "2 Phasen werden erkannt")

        LP1.A3 = 1
        Scheduler().test_callAll()
        LP1.zaehle_phasen()
        Scheduler().test_callAll()
        self.assertEqual(1, data.get('lp/1/countPhasesInUse'),
                         "3 Phasen werden erkannt")
Exemple #14
0
 def setup(self):
     """Subscribe to set topics"""
     self.bulk_config()
     self.logger.debug('Subscribing.')
     self.client.subscribe("openWB/set/#", 2)
     self.client.subscribe("openWB/config/set/#", 2)
     scheduler = Scheduler()
     scheduler.registerData(["*"], self)
     scheduler.registerTimer(
         10, self.publishLiveData
     )  # TODO: React on Chargepoint  end-of-loop event
     scheduler.registerEvent(EventType.configupdate, self.newconfig)
     scheduler.registerEvent(EventType.resetDaily, self.cut_live)
Exemple #15
0
 def setup(self, config):
     super().setup(config)
     host = config[self.configprefix + '_ip']
     assert host is not None, "Host für %s notwenig! (Setting %s_ip)" % (
         self.configprefix, self.configprefix)
     self.instances = config.get(self.configprefix + '_instances', 1)
     if config.get(self.configprefix + '_type') == 'modbus':
         self.instance = ModbusWR(host, self.instances)
     else:  # dashboard
         self.instance = SMADASH(host)
         assert self.instances == 1, "Dashboard Tripower can only have one instance."
     super().setup(config)
     Scheduler().registerTimer(10, self.loop)
Exemple #16
0
    def test_dummyEVU(self):
        OpenWBconfig('resources/test.conf')
        module = EVUModule()
        self.assertIsNotNone(module.modul)

        EVU = module.modul
        data = openWBValues()
        EVU.P = 1000
        Scheduler().test_callAll()

        self.assertEqual(EVU.P, data.get('evu/W'),
                         "EVU power has been reported")
        self.assertIsNone(data.get('evu/ASchieflast', None),
                          "Keine Schieflast ohne Phasenströme")

        EVU.A1 = 1
        EVU.A2 = 3
        EVU.A3 = 6

        Scheduler().test_callAll()
        self.assertEqual(5, data.get('evu/ASchieflast'),
                         "EVU Schieflast has been calculated")
        EVU.kwhIn = 5
        EVU.kwhOut = 10
        Scheduler().test_callAll()
        self.assertEqual(EVU.kwhIn, data.get('evu/WhImported'),
                         "EVU energy imported has been reported")
        self.assertEqual(EVU.kwhOut, data.get('evu/WhExported'),
                         "EVU energy exported has been reported")

        self.assertEqual(EVU.kwhIn, data.get('evu/DailyYieldImportKwh'),
                         "EVU energy imported has been reported (Daily)")
        self.assertEqual(EVU.kwhOut, data.get('evu/DailyYieldExportKwh'),
                         "EVU energy exported has been reported(Daily)")
        self.assertEqual(EVU.kwhIn, data.get('evu/MonthlyYieldImportKwh'),
                         "EVU energy imported has been reported (Monthly)")
        self.assertEqual(EVU.kwhOut, data.get('evu/MonthlyYieldExportKwh'),
                         "EVU energy exported has been reported (Monthly)")
Exemple #17
0
    def test_data(self):
        OpenWBconfig('resources/test.conf')
        module = PVModule()
        self.assertEqual(2, len(module.modules))

        WR1, WR2 = module.modules
        data = openWBValues()
        WR1.P = 1000
        WR2.P = 2000
        Scheduler().test_callAll()

        self.assertEqual(WR1.P, data.get('pv/1/W'),
                         "WR1 power has been reported")
        self.assertEqual(WR2.P, data.get('pv/2/W'),
                         "WR2 power has been reported")
        self.assertEqual(WR1.P + WR2.P, data.get('pv/W'),
                         "sum power has been reported")

        Scheduler().test_callAll()
        WR1.Wh = 5
        WR2.Wh = 10
        Scheduler().test_callAll()

        self.assertEqual(WR1.Wh, data.get('pv/1/kwh'),
                         "WR1 generation has been reported")
        self.assertEqual(WR2.Wh, data.get('pv/2/kwh'),
                         "WR2 generation has been reported")
        self.assertEqual(WR1.Wh + WR2.Wh, data.get('pv/WhCounter'),
                         "Sum generation has been reported")

        self.assertEqual(WR1.Wh, data.get('pv/1/DailyKwh'),
                         "WR1 generation has been reported (Daily)")
        self.assertEqual(WR1.Wh, data.get('pv/1/MonthlyKwh'),
                         "WR1 generation has been reported (Monthly)")
        self.assertEqual(WR1.Wh + WR2.Wh, data.get('pv/DailyYieldKwh'),
                         "Sum generation has been reported (Daily)")
        self.assertEqual(WR1.Wh + WR2.Wh, data.get('pv/MonthlyYieldKwh'),
                         "Sum generation has been reported (Monthly)")
Exemple #18
0
 def __init__(self, instance_id: int):
     super().__init__(daemon=True)
     name = self.__class__.__name__
     self.trigger = Event()  # A trigger to start the module
     self.finished = Event()  # A trigger to signal that the module has run
     self.trigger.clear()
     self.finished.clear()
     if hasattr(self.__class__,
                'multiinstance') and self.__class__.multiinstance:
         self.id = instance_id
         name += '_' + str(instance_id)
     self.name = name
     self.logger = logging.getLogger(self.name)
     self.configprefix = None  # Provided during setup
     self.offsets = {}  # Place for storing offsets for daily data
     if hasattr(self, 'event'):  # Register general event handler
         Scheduler().registerEvent(None, self.event)
Exemple #19
0
    def send(self, data: dict) -> None:
        if 'W' in data:  # Only for normal data packages
            if "boolPlugStat" not in data:
                data["boolPlugStat"] = not self.is_blocked
            if "boolChargeStat" not in data:
                data["boolChargeStat"] = self.is_charging
            if "countPhasesInUse" not in data:
                data['countPhasesInUse'] = self.phasen
            if "kwh" not in data:
                data['kwh'] = 0

            # Handle Ladung seit Plug / Ladung seit Chargestart
            plugged = data['boolPlugStat']
            charging = data['boolChargeStat']
            chargedkwh = data['kwh']
            self.offsets['chargedW'] += data['W']
            data['kWhChargedSincePlugged'] = self.offsetted(
                'plugged', 'kwh', chargedkwh) if plugged else 0
            data['kWhActualCharged'] = self.offsets[
                'chargedW'] / 720000  # Einheit: W*Zykluszeit => /(3600/t)/1000
            #  self.offsetted('charge', 'kwh', chargedkwh)
            if plugged and not self.plugged:
                self.reset_offset('plugged', 'kwh')
                self.logger.info(f'LP{self.id} plugged in at {chargedkwh} kwh')
                Scheduler().signalEvent(
                    OpenWBEvent(EventType.resetEnergy, self.id))
            if charging and not self.charging:
                self.reset_offset('charge', 'kwh')
                self.offsets['chargedW'] = 0
                self.logger.info('Start charging at %i kwh' % chargedkwh)
                #  self.setP = self.actP  # Initialisiere setP falls externer Start
            self.plugged = plugged
            self.charging = charging
            data["DailyKwh"] = self.offsetted('daily', 'kwh', data['kwh'])

        self.master.send(DataPackage(self, data))
Exemple #20
0
    def messagehandler(self, msg):
        """Handle incoming requests"""
        republish = False
        getter_topic = msg.topic.replace('openWB/',
                                         '').replace('/set/', '/get/')
        #     self.logger.info("receive: %s = %s" % (repr(msg.topic), repr(msg.payload)))
        try:
            val = int(msg.payload)

#        self.logger.info("Value: %i" % val)
        except ValueError:
            val = None
        try:
            if msg.topic == "openWB/config/set/pv/regulationPoint":  # Offset (PV)
                if val is not None and -300000 <= val <= 300000:
                    republish = True
                    self.core.setconfig('offsetpv', val)
            elif msg.topic == "openWB/config/set/pv/priorityModeEVBattery":  # Priorität Batt/EV
                if val is not None and 0 <= val <= 2:
                    republish = True
                    self.core.setconfig('speicherpveinbeziehen', val)
            elif msg.topic == "openWB/config/set/pv/nurpv70dynw":
                republish = True
                self.core.setconfig('offsetpvpeak', val)
            elif re.match("openWB/set/lp/(\\d)/ChargePointEnabled",
                          msg.topic):  # Chargepoint en/disable
                device = int(re.search('/lp/(\\d)/', msg.topic).group(1))
                republish = True
                self.core.data.update(
                    DataPackage(self,
                                {'lp/%i/ChargePointEnabled' % device: val}))
            elif msg.topic.startswith(
                    "openWB/config/set/sofort/"):  # Sofortladen...
                device = int(re.search('/lp/(\\d)/', msg.topic).group(1))
                if 1 <= device <= 8:
                    republish = True
                    if msg.topic.endswith('current'):
                        if val is not None and 6 <= val <= 32:
                            self.core.setconfig('lpmodul%i_sofortll' % device,
                                                val)
                    elif msg.topic.endswith(
                            'chargeLimitation'):  # Limitierung Modus
                        if val is not None and 0 <= val <= 2:
                            self.core.setconfig('msmoduslp%i' % device, val)
                            self.publish_config(
                                "lp/%i/boolDirectModeChargekWh" % device,
                                1 if val == 1 else 0)
                            self.publish_config(
                                "lp/%i/boolDirectChargeModeSoc" % device,
                                1 if val == 2 else 0)
                    elif msg.topic.endswith(
                            'energyToCharge'):  # Modus 1: Lademenge [kWh]
                        if val is not None and 0 <= val <= 100:
                            self.core.setconfig('lademkwh%i' % device, val)
                    elif msg.topic.endswith(
                            'socToChargeTo'):  # Modus 2: SOC [%]
                        if val is not None and 0 <= val <= 100:
                            self.core.setconfig('sofortsoclp%i' % device, val)
                    elif msg.topic.endswith('resetEnergyToCharge'):
                        republish = False
                        if msg.payload:
                            Scheduler().signalEvent(
                                OpenWBEvent(EventType.resetEnergy, device))

            elif msg.topic == "openWB/config/set/pv/stopDelay":
                if val is not None and 0 <= val <= 10000:
                    republish = True
                    self.core.setconfig('abschaltverzoegerung', val)
            elif msg.topic.startswith(
                    'openWB/config/set/lp/'):  # Ladepunkt Konfiguration
                self.logger.info("LP message")
                device = int(re.search('/lp/(\\d)', msg.topic).group(1))
                if re.search("/ChargeMode", msg.topic):  # Chargemode
                    mode = Chargemap(val)
                    self.logger.info(f'ChargeMode lp{device} = {mode}')
                    if 1 <= device <= 8:
                        self.core.setconfig('lpmodul%i_mode' % device,
                                            mode.name)
                elif re.search("/alwaysOn", msg.topic):
                    self.logger.info(f'AlwaysOn lp{device} = {msg.payload}')
                    if 1 <= device <= 8:
                        republish = True
                        self.core.setconfig('lpmodul%i_alwayson' % device,
                                            bool(int(msg.payload)))
            elif msg.topic == "openWB/set/graph/RequestDayGraph":
                # Anforderung eines Daily graphs.
                # Format Wert: yyyymmdd
                # Antwort: openWB/system/DayGraphData1<n>, n=1..12 je 25 Zeilen
                # Herkunft: web/logging/data/<yyyymm>.csv erzeugt von Cronjob "cron5min.sh"
                # echo $(date +%H%M),$bezug,$einspeisung,$pv,$ll1,$ll2,$ll3,$llg,$speicheri,$speichere,$verbraucher1,$verbrauchere1,$verbraucher2,$verbrauchere2,$verbraucher3,$ll4,$ll5,$ll6,$ll7,$ll8,$speichersoc,$soc,$soc1,$temp1,$temp2,$temp3,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$d10,$temp4,$temp5,$temp6 >> $dailyfile.csv
                if 1 <= val <= 20501231:
                    subprocess.run([
                        basePath + '../../runs/senddaygraphdata.sh',
                        msg.payload
                    ])
            elif msg.topic == 'openWB/set/graph/RequestMonthGraph':
                # Anforderung eines Month graphs.
                # Format Wert: yyyymm
                # Antwort: openWB/system/MonthGraphData<n>, n=1..12 je 25 Zeilen
                # Herkunft: web/logging/data/<yyyymm>.csv erzeugt von Cronjob "cronnightly.sh"
                # echo $(date +%Y%m%d),$bezug,$einspeisung,$pv,$ll1,$ll2,$ll3,$llg,$verbraucher1iwh,$verbraucher1ewh,$verbraucher2iwh,$verbraucher2ewh,$ll4,$ll5,$ll6,$ll7,$ll8,$speicherikwh,$speicherekwh,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$d10 >> $monthlyfile.csv
                if 1 <= val <= 20501231:
                    subprocess.run([
                        basePath + '../../runs/sendmonthgraphdata.sh',
                        msg.payload
                    ])
            elif msg.topic == "openWB/set/graph/RequestLiveGraph":
                if val == 1:
                    subprocess.run(basePath +
                                   "../../runs/sendlivegraphdata.sh")
                else:
                    self.publish_data("system/LiveGraphData", "empty", qos=0)
            elif msg.topic == "openWB/set/graph/RequestLLiveGraph":
                if val == 1:
                    subprocess.run(basePath +
                                   "../../runs/sendllivegraphdata.sh")
            elif getter_topic in self.configmapping:
                if val is not None and 0 <= val <= 10000:
                    republish = True
                    self.core.setconfig(self.configmapping[getter_topic], val)
            else:
                self.logger.info("Nix gefunden.")
        except IOError as e:  # Exception
            self.logger.exception("BAMM!", exc_info=e)
        if republish:
            #         self.logger.info("Re-publish: %s = %s" % (getter_topic, msg.payload))
            self.publish_config(getter_topic, msg.payload)
Exemple #21
0
 def setup(self):
     scheduler = Scheduler()
     scheduler.registerData(['*'], self)
Exemple #22
0
import os
import sys

mypath = os.path.dirname(os.path.realpath(__file__)) + '/'
sys.path.append(mypath + 'src')

from openWB import OpenWBCore, api
from openWB.Scheduling import Scheduler
from openWB.startup import init_system

if 'http_proxy' in os.environ:
   os.environ.pop('http_proxy')
if 'https_proxy' in os.environ:
   os.environ.pop('https_proxy')

level = logging.DEBUG if os.environ.get("DEBUG") == "1" else logging.INFO
logging.basicConfig(level=level, format='%(asctime)-15s %(message)s', filename="/var/log/openWB.log")

infologgers = ['Adafruit_I2C.Device.Bus.1.Address.0X40', 'pymodbus']
for logger in infologgers:
   logging.getLogger(logger).setLevel(logging.INFO)

init_system()
core = OpenWBCore.OpenWBCore().setup()

# Start the API
#api = api.OpenWBAPI(core)
#api.start()

Scheduler().run()
Exemple #23
0
 def setup(self, config):
     super().setup(config)
     self.kwh = 0
     self.minI = config['minimalstromstaerke']
     self.maxI = config['maximalstromstaerke']
     Scheduler().registerTimer(1, self.loop)
Exemple #24
0
 def setup(self, config):
     self.P = 0
     self.Wh = 0
     Scheduler().registerTimer(1, self.loop)
Exemple #25
0
    def test_dummyLP(self):
        OpenWBconfig('resources/test.conf')
        data = openWBValues()
        module = LPModule()
        self.assertEqual(1, len(module.modules))
        self.assertEqual(1, data.get('lp/1/boolChargePointConfigured'),
                         'LP1 configured')
        self.assertEqual(1, data.get('lp/1/ChargePointEnabled'), 'LP1 enabled')

        LP1 = module.modules[0]
        LP1.set(1300)
        with self.subTest('Geringe Leistung'):
            LP1.actP = 200
            Scheduler().test_callAll()
            self.assertFalse(data.get('lp/1/boolChargeStat'),
                             "Fahrzeug lädt nicht")

        with self.subTest('Höhere Leistung'):
            LP1.actP = 1200
            LP1.A = 6
            LP1.A1 = 5.5

            Scheduler().test_callAll()

            self.assertEqual(LP1.actP, data.get('lp/1/W'),
                             "LP1 Leistung wird übertragen")
            self.assertEqual(LP1.A, data.get('lp/1/AConfigured'),
                             "LP1 Strom wird übertragen")
            self.assertEqual(LP1.actP, data.get('global/WAllChargePoints'),
                             "Summenleistung wird übertragen")
            self.assertTrue(data.get('lp/1/boolChargeStat'), "Fahrzeug lädt")

        with self.subTest('Lademenge'):
            LP1.kwh = 10
            Scheduler().test_callAll()
            self.assertEqual(LP1.kwh, data.get('lp/1/kwh'),
                             "Energie (Gesamt) wird übertragen")
            self.assertEqual(LP1.kwh, data.get('lp/1/DailyKwh'),
                             "Energie (Daily) wird übertragen")
            self.assertEqual(LP1.kwh, data.get('lp/1/kWhActualCharged'),
                             "Energie (Seit Ladebeginn) wird übertragen")
            self.assertEqual(LP1.kwh, data.get('lp/WhCounter'),
                             "Energie (Gesamtsumme) wird übertragen")
            self.assertEqual(LP1.kwh, data.get('lp/DailyYieldKwh'),
                             "Energie (Daily Summe) wird übertragen")

        with self.subTest('Neuer Ladezyklus'):
            LP1.actP = 10
            Scheduler().test_callAll()
            self.assertFalse(data.get('lp/1/boolChargeStat'),
                             "Fahrzeug lädt nicht")
            LP1.actP = 2400
            Scheduler().test_callAll()
            self.assertTrue(data.get('lp/1/boolChargeStat'), "Fahrzeug lädt")
            LP1.kwh += 5
            Scheduler().test_callAll()
            self.assertEqual(15, data.get('lp/1/kwh'),
                             "Energie (Gesamt) wird übertragen")
            self.assertEqual(15, data.get('lp/1/DailyKwh'),
                             "Energie (Daily) wird übertragen")
            self.assertEqual(5, data.get('lp/1/kWhActualCharged'),
                             "Energie (Seit Ladebeginn) wird übertragen")
            self.assertEqual(15, data.get('lp/1/kWhChargedSincePlugged'),
                             "Energie (Seit Plugged) wird übertragen")
            self.assertEqual(15, data.get('lp/WhCounter'),
                             "Energie (Gesamtsumme) wird übertragen")
            self.assertEqual(15, data.get('lp/DailyYieldKwh'),
                             "Energie (Daily Summe) wird übertragen")
Exemple #26
0
    def loop(self) -> None:
        properties = [lp.get_props() for lp in self.regler.values()]
        arbitriert = dict([(id, 0) for id in self.regler.keys()])
        self.logger.debug(f"Reglergruppe {self.mode} LP Props: {properties!r}")
        uberschuss = self.data.get('global/uberschuss')
        for id, regler in self.regler.items():
            prefix = 'lp/%i/' % id
            limitierung = self.config.get('msmoduslp%i' % id)
            if self.mode not in ['standby', 'stop']:
                if limitierung == 1 and self.config.get(
                        'lademkwh%i' % id):  # Limitierung: kWh
                    if self.data.get(prefix + 'W') == 0:
                        restzeit = "---"
                    else:
                        restzeit = int(
                            (self.config.get('lademkwh%i' % id) -
                             self.data.get(prefix + 'kWhActualCharged', 0)) *
                            1000 * 60 / self.data.get('lp/%i/W' % id))
                    # print(f"LP{id} Ziel: {self.config.get('lademkwh%i' % id)} Akt: {self.data.get(prefix + 'kWhActualCharged')} Leistung: {self.data.get(prefix + 'W')} Restzeit: {restzeit}")
                    self.data.update(
                        DataPackage(
                            regler.wallbox,
                            {prefix + 'TimeRemaining': f"{restzeit} min"}))
                    if self.config.get(
                            'lademkwh%i' %
                            id) <= self.data.get(prefix + 'kWhActualCharged'):
                        self.logger.info(
                            f"Lademenge erreicht: LP{id} {self.config.get('lademkwh%i' % id)}kwh"
                        )
                        from openWB.OpenWBCore import OpenWBCore
                        OpenWBCore().setconfig(
                            regler.wallbox.configprefix + '_mode', "standby")
                        Scheduler().signalEvent(
                            OpenWBEvent(EventType.resetEnergy, id))
                elif limitierung == 2:  # Limitierung: SOC
                    pass  # TODO
        if self.mode == 'sofort':
            for id, regler in self.regler.items():
                power = amp2power(
                    self.config.get("lpmodul%i_sofortll" % id, 6),
                    regler.wallbox.phasen)
                if regler.wallbox.setP != power:
                    regler.wallbox.set(power)

        elif self.mode in ['stop', 'standby']:
            for regler in self.regler.values():
                if regler.wallbox.setP != 0 or regler.wallbox.is_charging:
                    self.logger.info(
                        f"(LP {regler.wallbox.id}: {regler.wallbox.setP}W -> Reset"
                    )
                    regler.wallbox.set(0)
        elif uberschuss > self.limit:  # Leistungserhöhung
            deltaP = uberschuss - self.limit
            # Erhöhe eingeschaltete LPs
            for r in sorted(filter(lambda r: 'min+P' in r and 'on' in r.flags,
                                   properties),
                            key=lambda r: r['min+P'].priority):
                p = self.get_increment(r, deltaP)
                if p is not None and self.schieflast_nicht_erreicht(r.id):
                    # Erhöhe bei Asymmetrie nur 3-phasen-Boxen
                    self.logger.debug(f"LP {r.id} bekommt +{p}W von {deltaP}W")
                    arbitriert[r.id] = p
                    deltaP -= p
                    if deltaP <= 0:
                        break
            # Schalte LPs mit höchster Prio ein
            candidates = unroll(
                groupby(filter(lambda r: 'min+P' in r and 'off' in r.flags,
                               properties),
                        key=lambda r: r['min+P'].priority))
            if candidates:
                highest_prio = max(candidates.keys())
                candidates = candidates[highest_prio]
                # Budget zum Einschalten: Erstmal der Überschuss
                budget = uberschuss - self.limit
                if self.mode == "pv":
                    budget -= self.hysterese
                # Zusätzliches Budget kommt vom Regelpotential eingeschalteter LPs gleicher oder niedrigerer Prio
                budget += sum(r['max-P'].value for r in filter(
                    lambda r: 'max-P' in r and 'min' not in r.flags and r[
                        'max-P'].priority <= highest_prio, properties))
                for r in candidates:
                    if self.get_increment(
                            r, budget
                    ) is not None and self.schieflast_nicht_erreicht(r.id):
                        self.logger.info(
                            f"Budget: {budget}; LP {r.id} min+P {r['min+P'].value} passt noch"
                        )
                        arbitriert[r.id] = r['min+P'].value
                        budget -= r['min+P'].value
        elif uberschuss < self.limit:  # Leistungsreduktion
            deltaP = self.limit - uberschuss
            for r in sorted(filter(
                    lambda r: 'min-P' in r and 'min' not in r.flags,
                    properties),
                            key=lambda r: r['min-P'].priority):
                p = self.get_decrement(r, deltaP)
                if p is not None:
                    self.logger.debug(
                        f"LP {r.id} Reduzierung -{p}W von -{deltaP}W")
                    arbitriert[r.id] = -p
                    deltaP -= p
                    if deltaP <= 0:
                        break
            # Schalte LPs aus
            deltaP = self.limit - uberschuss
            if self.mode == "peak":
                deltaP -= self.hysterese
            for r in sorted(filter(lambda r: 'min' in r.flags, properties),
                            key=lambda r: r['min-P'].priority):
                if self.get_decrement(r, deltaP) is not None:
                    self.logger.info(
                        f"Abschalten LP {r.id} soll {r['min-P'].value}W freigeben."
                    )
                    arbitriert[r.id] = -r['min-P'].value
                    deltaP -= r['min-P'].value

        for ID, inc in arbitriert.items():
            self.regler[ID].request(inc)
Exemple #27
0
 def __init__(self):
     Scheduler().registerData(
         ['evu/W', 'pv/W', 'global/WAllChargePoints', 'housebattery/W'],
         self)
     self.data = openWBValues()
     self.config = OpenWBconfig()
Exemple #28
0
 def setup(self, config):
    self.pwm = Ada.PCA9685(address=config.get(self.configprefix + '_address'))
    self.pwm.set_pwm_freq(100)
    self.last = {'pv': 0, 'soc': 0, 'grid': -1000, 'batt': -1000, 'green': 0, 'red': 0}
    Scheduler().registerData(mapping.keys(), self)
    Scheduler().registerTimer(10, self.leds)
Exemple #29
0
 def test_scheduling(self):
    Scheduler().registerTimer(5, self.listener1.loop)
    Scheduler().registerTimer(10, self.listener2.loop)
    Scheduler().run(simulated=True)
    self.assertEqual(2, self.listener1.executed)
    self.assertEqual(1, self.listener2.executed)