Control charging of EBike via Sonoff POW

Hi,

i want to control the charging of my EBike via energy measurement. The charging curve of a lipo battery changes from CC (constant current) to CV (constant voltage) at a SOC of 90%. Therefore also the power consumption of the charger is constant in the CC phase and tends towards zero in CV phase.

To increase the battery life, I want to switch of charging at a SOC of 90%. Therefore i measure the power of the charger in the CC phase. If the power drops below 80% of this value, the rule switches of the charger.

This is what i currently ended up with:

var Number EBikeLadecontrollerStart = 0
var Number EBikeLadecontrollerMaxPower= 0
var Number PowerTreshold = 0
var Boolean AutoAbschaltung = false

rule EBikeLadecontroller

when
        Item EBikeLadecontrollerTotal changed or
        Item EBikeLadecontrollerPower changed
then
        var EBikeLadecontrollerTotal = (EBikeLadecontrollerTotal.state as Number) * 1000
        if(EBikeLadecontrollerPower.state > EBikeLadecontrollerMaxPower) {
                EBikeLadecontrollerMaxPower = EBikeLadecontrollerPower.state
                PowerTreshold = (EBikeLadecontrollerTreshold.state as Number) / 100 * EBikeLadecontrollerMaxPower
                logInfo("Ladecontroller", "Maximalwert {}", EBikeLadecontrollerMaxPower)
                logInfo("Ladecontroller", "Abschaltschwelle {}", PowerTreshold)
        }

        if(EBikeLadecontrollerPower.state < PowerTreshold && AutoAbschaltung == true) {
                EBikeLadecontroller.sendCommand(OFF)
                logInfo("Ladecontroller", "Abschaltschwelle erreicht")
                logInfo("Ladecontroller", "Abschaltschwelle {}", PowerTreshold)
                logInfo("Ladecontroller", "Leistung {}", EBikeLadecontrollerPower.state)
        }


        EBikeLadecontrollercharged.postUpdate(EBikeLadecontrollerTotal - EBikeLadecontrollerStart )

end

rule Reset

when
        Item EBikeLadecontroller changed from OFF to ON
then
                EBikeLadecontrollerStart = EBikeLadecontrollerTotal
                EBikeLadecontrollercharged.postUpdate(0)
                EBikeLadecontrollerMaxPower = 0
                AutoAbschaltung = false
                createTimer(now.plusSeconds(60), [|
                        AutoAbschaltung = true  
                        logInfo("Ladecontroller", "Autoabschaltung {}", AutoAbschaltung)
                ])
                logInfo("Ladecontroller", "Ladevorgang gestartet, Startwert {}", EBikeLadecontrollerStart)
                logInfo("Ladecontroller", "Maximalwert {}", EBikeLadecontrollerMaxPower)
                logInfo("Ladecontroller", "Autoabschaltung {}", AutoAbschaltung)
end

The rule does the following:
Determines the max. power consumption of the charger.
Checks if the Power drops below the power treshold after 60 seconds from charging start.
Displays the charged energy in Wh.

The rule works already, but I’m getting the following error:

Rule 'EBikeLadecontroller': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.lib.NumberExtensions.operator_minus(java.lang.Number,java.lang.Number) on instance: null

I think it has to do with converting values from kWh to Wh.

Where is my mistake?

I’m amazed that works at all without quotemarks
rule "EBikeLadecontroller"

A word of warning on that subject, every rule must have a unique “name” there.

Okay, we can guess where that comes from as it involves ‘minus’.
(You can add temporary logInfo() messages to your rules to track progress when investigating error messages.)

This is a bit worrying though …

That’s not illegal, but it might not do what you expect.

You seem to have an Item named EBikeLadecontrollerTotal ?

But in the first line of your rule you declare a new variable also named EBikeLadecontrollerTotal
All references to name EBikeLadecontrollerTotal in your rule will now get that variable, not the “real” Item.
That includes the use of EBikeLadecontrollerTotal.state , which makes a circular definition of the variable by itself. I’m surprised that doesn’t throw an error, perhaps because it hasn’t yet finished making the “new” variable.

Yes, i have a item EBikeLadecontrollerTotal, which displays the total amount of energy.

The reason why i use the variable is, that i want to convert the value kWh to Wh. I’ve tried to convert it in the sitemap as described here. But i could not find out, why this wasn’t working.

I done some rework on my code:

var Number EBikeLadecontrollerStart = 0
var Number EBikeLadecontrollerMaxPower= 0
var Number PowerTreshold = 0
var Boolean AutoAbschaltung = false

rule "EBikeLadecontroller"

when
    Item EBikeLadecontrollerTotal changed or
    Item EBikeLadecontrollerPower changed
then
//      var EBikeLadecontrollerTotal = (EBikeLadecontrollerTotal.state as Number) * 1000
    if(EBikeLadecontrollerPower.state > EBikeLadecontrollerMaxPower) {
            EBikeLadecontrollerMaxPower = EBikeLadecontrollerPower.state
            PowerTreshold = (EBikeLadecontrollerTreshold.state as Number) / 100 * EBikeLadecontrollerMaxPower
            logInfo("Ladecontroller", "Maximalwert {}", EBikeLadecontrollerMaxPower)
            logInfo("Ladecontroller", "Abschaltschwelle {}", PowerTreshold)
    }

    if(EBikeLadecontrollerPower.state < PowerTreshold && AutoAbschaltung == true) {
            EBikeLadecontroller.sendCommand(OFF)
            logInfo("Ladecontroller", "Abschaltschwelle erreicht")
            logInfo("Ladecontroller", "Abschaltschwelle {}", PowerTreshold)
            logInfo("Ladecontroller", "Leistung {}", EBikeLadecontrollerPower.state)
    }


    logInfo("Ladecontroller", "Gesamtenergie {}", EBikeLadecontrollerTotal.state)
    logInfo("Ladecontroller", "Startwert {}", EBikeLadecontrollerStart)
    EBikeLadecontrollercharged.postUpdate((EBikeLadecontrollerTotal.state as Number - EBikeLadecontrollerStart)*1000)

end

rule "Reset"

when
    Item EBikeLadecontroller changed from OFF to ON
then
            EBikeLadecontrollerStart = EBikeLadecontrollerTotal.state
            EBikeLadecontrollercharged.postUpdate(0)
            EBikeLadecontrollerMaxPower = 0
            AutoAbschaltung = false
            createTimer(now.plusSeconds(60), [|
                    AutoAbschaltung = true  
                    logInfo("Ladecontroller", "Autoabschaltung {}", AutoAbschaltung)
            ])
            logInfo("Ladecontroller", "Ladevorgang gestartet, Startwert {}", EBikeLadecontrollerStart)
            logInfo("Ladecontroller", "Maximalwert {}", EBikeLadecontrollerMaxPower)
            logInfo("Ladecontroller", "Autoabschaltung {}", AutoAbschaltung)
end

Now, it is working… But i don’t know if the code is “clean”.