def start(self): self.state = ChargePlanState.STATE_INIT # main state machine while True: self.printToLogfile("State: " + str(self.state)) ################################################################################################## # STATE_INIT ################################################################################################## if self.state == ChargePlanState.STATE_INIT: try: # load configuration from JSON file with open('config.json') as configFile: self.config = json.load(configFile) # Initialize Wallbox charger = Wallbox.goEcharger( self.config["wallbox"]["IP"], self.config["wallbox"]["absolutMaxCurrent"]) # Uncomment this to use wallbox simulator for developing #charger = Wallbox.goEchargerSimulation(self.config["wallbox"]["IP"], self.config["wallbox"]["absolutMaxCurrent"]) # Initialize Measurement weatherSensorList = list() for measurement in self.config["measurements"]: if measurement["type"] == "Swissmeteo": weatherSensorList.append( Measurement.Swissmeteo(measurement["station"], measurement["modes"])) elif measurement["type"] == "Solarlog": weatherSensorList.append( Measurement.SolarLog(measurement["url"], measurement["username"], measurement["password"], measurement["modes"])) elif measurement["type"] == "Fronius": weatherSensorList.append( Measurement.Fronius(measurement["url"], measurement["deviceID"], measurement["modes"])) elif measurement["type"] == "Smartfox": weatherSensorList.append( Measurement.Smartfox(measurement["ip"], measurement["modes"])) else: self.printToLogfile( "Invalid weatherSensor definition") charger.allowCharging(False) self.allowCharging = False # internal state new_state = ChargePlanState.STATE_NO_CAR except IOError: # probably connection error to wallbox, try again self.printToLogfile("Wallbox IOError") time.sleep(self.config["timing"]["waitAfterErrorSeconds"]) new_state = ChargePlanState.STATE_INIT ################################################################################################## # STATE_NO_CAR ################################################################################################## elif self.state == ChargePlanState.STATE_NO_CAR: try: charger.readStatus() self.printToLogfile("Charger state: " + str(charger.state)) if charger.state == Wallbox.WallboxState.STATE_READY_NO_CAR: self.printToLogfile("Still no car connected, wait.") time.sleep( self.config["timing"]["waitWithoutCarSeconds"]) elif (charger.state == Wallbox.WallboxState.STATE_WAITING_FOR_CAR) or ( charger.state == Wallbox.WallboxState.STATE_CHARGING): self.printToLogfile("Car connected.") self._goal = None self.deadline = None self.maxEnergy = 0 self.limitToMaxEnergy = False new_state = ChargePlanState.STATE_CHARGING elif charger.state == Wallbox.WallboxState.STATE_FINISHED_CAR_STILL_CONNECTED: if self.allowCharging == False: self.printToLogfile( "Car connected but probably not really finished" ) new_state = ChargePlanState.STATE_CHARGING else: self.printToLogfile( "Car connected but already finished") new_state = ChargePlanState.STATE_FINISHED IOerror_count = 0 except IOError: # probably connection error to wallbox, try again IOerror_count = IOerror_count + 1 self.printToLogfile("Wallbox IOError") # if error count is too high, re-init everything if (IOerror_count > self.config["timing"]["connectionMaxRetrys"]): new_state = ChargePlanState.STATE_INIT else: time.sleep( self.config["timing"]["waitAfterErrorSeconds"]) new_state = ChargePlanState.STATE_NO_CAR ################################################################################################## # STATE_CHARGING ################################################################################################## elif self.state == ChargePlanState.STATE_CHARGING: try: charger.readStatus() self.printToLogfile("Wallbox state: " + str(charger.state)) self.power = charger.currentPower self.energy = charger.energy # check state of car and decide on consequences if charger.state == Wallbox.WallboxState.STATE_READY_NO_CAR: # car disconnected new_state = ChargePlanState.STATE_FINISHED elif charger.state == Wallbox.WallboxState.STATE_FINISHED_CAR_STILL_CONNECTED: if self.allowCharging == True: # Car says it's finished during charging, so battery is full new_state = ChargePlanState.STATE_FINISHED else: # Car says it's finished when charging is not allowed, so battery is NOT full. new_state = ChargePlanState.STATE_CHARGING else: new_state = ChargePlanState.STATE_CHARGING # take further actions if state should not be left if new_state == ChargePlanState.STATE_CHARGING: dateObjectNow = datetime.datetime.now() # Get maximum current from weather sensors. If multiple sensors are configured, # try all of them but stop as soon as one of them returns a valid value maxAllowedCurrent = None for weatherSensor in weatherSensorList: if maxAllowedCurrent == None: try: maxAllowedCurrent = weatherSensor.getMaxAllowedCurrent( self.power, self.mode) except IOError: # probably connection error to sensor self.printToLogfile( "WeatherSensor IOError: " + str(weatherSensor)) # Check returned value from weather sensors and react if maxAllowedCurrent == None: self.printToLogfile( "No weathersensor has returned a value.") maxAllowedCurrent = 0 time.sleep( self.config["timing"]["waitWithoutSunSeconds"]) new_state = ChargePlanState.STATE_CHARGING else: # Check if deadline is reached if self.deadline != None: if dateObjectNow > self.deadline: deadlineReached = True else: deadlineReached = False else: deadlineReached = False # Decide on charging depending on deadline and measurements if deadlineReached: # Deadline reached, charge charger.allowCharging(True) self.allowCharging = True # internal state self.printToLogfile( "Charge: deadline reached. Power: " + str(self.power)) charger.setMaxCurrent(self.config["wallbox"] ["absolutMaxCurrent"]) charger.setMaxEnergy(self.limitToMaxEnergy, self.maxEnergy) time.sleep(self.config["timing"] ["waitChargingSeconds"]) new_state = ChargePlanState.STATE_CHARGING else: if maxAllowedCurrent > 0: charger.allowCharging(True) self.allowCharging = True # internal state charger.setMaxCurrent(maxAllowedCurrent) charger.setMaxEnergy( self.limitToMaxEnergy, self.maxEnergy) self.printToLogfile( "Charge: getMaxAllowedCurrent: " + str(maxAllowedCurrent) + " power: " + str(self.power)) time.sleep(self.config["timing"] ["waitChargingSeconds"]) new_state = ChargePlanState.STATE_CHARGING else: charger.allowCharging(False) self.allowCharging = False # internal state self.printToLogfile( "No sun, don't charge, wait.") time.sleep(self.config["timing"] ["waitWithoutSunSeconds"]) new_state = ChargePlanState.STATE_CHARGING IOerror_count = 0 except IOError: # probably connection error to wallbox, try again IOerror_count = IOerror_count + 1 self.printToLogfile("Wallbox IOError") # if error count is too high, re-init everything if (IOerror_count > self.config["timing"]["connectionMaxRetrys"]): new_state = ChargePlanState.STATE_INIT else: time.sleep( self.config["timing"]["waitAfterErrorSeconds"]) new_state = ChargePlanState.STATE_CHARGING ################################################################################################## # STATE_FINISHED ################################################################################################## elif self.state == ChargePlanState.STATE_FINISHED: try: charger.readStatus() charger.setMaxCurrent( self.config["wallbox"]["absolutMaxCurrent"]) self.printToLogfile("Charger state: " + str(charger.state)) if charger.state == Wallbox.WallboxState.STATE_FINISHED_CAR_STILL_CONNECTED: self.printToLogfile( "Charging finished, car still connected") time.sleep( self.config["timing"]["waitAfterFinishedSeconds"]) elif charger.state == Wallbox.WallboxState.STATE_READY_NO_CAR: charger.allowCharging(False) self.allowCharging = False # internal state self.printToLogfile( "Charging finished, car disconnected") new_state = ChargePlanState.STATE_NO_CAR time.sleep( self.config["timing"]["waitWithoutCarSeconds"]) elif charger.state == Wallbox.WallboxState.STATE_WAITING_FOR_CAR or charger.state == Wallbox.WallboxState.STATE_CHARGING: self.printToLogfile( "Car starts charging again, probably pre-Heat") new_state = ChargePlanState.STATE_FINISHED time.sleep( self.config["timing"]["waitAfterFinishedSeconds"]) IOerror_count = 0 except IOError: # probably connection error to wallbox, try again IOerror_count = IOerror_count + 1 self.printToLogfile("Wallbox IOError") # if error count is too high, re-init everything if (IOerror_count > self.config["timing"]["connectionMaxRetrys"]): new_state = ChargePlanState.STATE_INIT else: time.sleep( self.config["timing"]["waitAfterErrorSeconds"]) new_state = ChargePlanState.STATE_FINISHED ################################################################################################## # STATE_ERROR ################################################################################################## elif self.state == ChargePlanState.STATE_ERROR: self.printToLogfile("Statemachine stuck in STATE_ERROR") time.sleep(self.config["timing"]["waitAfterErrorSeconds"]) ################################################################################################## # Undefined states ################################################################################################## else: self.printToLogfile("Error: Invalid state") time.sleep(self.config["timing"]["waitAfterFinishedSeconds"]) self.state = new_state