New OpenEMS CAN Bridge

Hello,
and of course, I’ll be happy to present the project in detail shortly:

We are currently (once again) developing our own battery storage system, based on a purchased BMS and, in parallel, a partially self-developed BMS. Both BMS units communicate via CAN, while our inverter a Pramac (REFU) runs via Modbus-TCP.
As the foundation for OpenEMS, we’re using a RevPi, and initial tests combining OpenEMS with the RevPi are looking very promising.

Professionally, my background is more in the Siemens PLC and Beckhoff world - so, more on the industrial PLC side. Privately, I’m more into web technologies like HTML, PHP, or VB(dot)NET, a bit of Python (because of Home Assistant) and, in that context, also some YAML code.

Now, to be honest, I have to admit that the OpenEMS documentation is really quite poor (sorry to say that). In my opinion, it doesn’t provide much information, and it also lacks the basics - like what needs to be done, when, and why.
Once we’ve made more progress with the project, I’d also like to contribute privately to improving the documentation.

For that, I first need to work my way through everything myself - and right now, I’m stuck at the CAN point.
I see in this thread that there’s something existing, and apparently, it worked quite well at some point, but how and where I need to go with this data is still far beyond the point I’ve been able to read or dig through so far.

Our system setup so far:

  • RevPi with the latest image (OS)
  • Docker + Portainer
  • InfluxDB2 in a container
  • OpenEMS in a container

Final point: We are a German company, and I also speak German. :wink:

Difficulty of CAN in terms of software is that it is just a transport, and protocol handling may vary a lot depending on the upper layers built on top of it.

With all this in mind, have you been able to run code linked in first post? I understand that documentation is far from perfect, however we can try making earlier code work and see how it breaks with latest OpenEMS core.

Hello, no.
My problem right now is: what do I do with the code?
How do I integrate it into my Docker environment?

Not really, you need to build above code, then build docker image. There is a way to add new/update existing modules in existing docker image, but it may turn in fairly long, manual and error prone process.

For now there is no easy way to do it.

So it would be better not to rely on the Docker variant.
Or rather, if I were to compile it and create a Docker image — do you know how much effort that would take?

Should I open a new thread for that?

@ldywicki already answered this question:

@Hispanic Thanks for introducing yourself and I am glad that - despite the lacking documentation - your initial tests were promising.

I personally do not have much experience in CAN communication; what I know is, that it can be difficult to handle it properly inside Java. So if you anyway use “a partially self-developed BMS” I assume it could be easier to just plug a Modbus Slave/Server library into your BMS code.

If that is not an option, I would start with an external CAN-to-Modbus converter, to get started and setup the entire system. If later you want to go in ‘mass-production’ you can still replace that device with a piece of software either on EMS or BMS side.

By the way: We are also using REFU battery inverters in some of our FENECON systems and projects. Looking forward to exchange experiences and code.

@stefan.feilmeier we are now in the process of bringing together all of our components and are still struggling a bit with our current REFU90k as an off-grid variant. Have you ever used one of these and can offer any tips?

For the CAN-to-Modbus variant, we have now written a software converter. That is working quite well so far and already handles the errors we can currently anticipate.

are still struggling a bit with our current REFU90k as an off-grid variant. Have you ever used one of these and can offer any tips?

Can you provide a link to the device? We have only used the REFUstore 50K / 88K in projects.

Sorry for the long wait, unfortunately I had a lot to do and other things on my table first. Attached is the link to the PDF (received directly from Pramac) for the Pramac PBI-90K BU. However, although we were sold an off-grid inverter, we are not allowed to use it, so the protocol was probably not extended for the off-grid part (not officially). Our 90k device has now been switched via software to an on-grid variant.

  1. Briefly about the inverter: the functions seem to be present. It runs and does what it is supposed to do for now; there seem to be a few adjustments in the Modbus registers, but nothing too dramatic.

  2. Now regarding our battery: this adapter is also running now. However, there are still a few things that are unclear to me. I am setting this part hard-coded for now, but it initially seems to have no effect:

this.channel(Battery.ChannelId.CHARGE_MAX_VOLTAGE)
    .setNextValue(770);
this.channel(Battery.ChannelId.CHARGE_MAX_CURRENT)
    .setNextValue(100);
this.channel(Battery.ChannelId.DISCHARGE_MIN_VOLTAGE)
    .setNextValue(720);
this.channel(Battery.ChannelId.DISCHARGE_MAX_CURRENT)
    .setNextValue(100);
  1. If the battery goes over 770 volts, nothing happens. Should something happen?
    What exactly does the (DIS)CHARGE_MAX_CURRENT affect? If I adjust it, the possible charge and discharge power also changes, but these values do not match "Allowed:-34706;32971".
    What exactly is affected here and how?

  2. And as a quick additional question, just in case I missed something:
    Is there already some kind of controller that can simply turn the battery system ON & OFF via the web interface? Kind of like taking it out of “automatic mode” and just switching it off manually.

Best regards,
Michael

By the way, here is the official PDF from Pramac:

https://www.pramac.com/file/112195

Hi Michael,

  1. :white_check_mark:
  2. CHARGE_MAX_VOLTAGE, etc.
    1. Those Channels are used by the Battery-Inverter implementations to set the registers inside the battery-inverter for its own safety controls. Example
    2. They are also used to calculate AllowedCharge/Discharge-power inside Generic-ESS (Code)
    3. You should see that allowed charge and discharge power is reduced e.g. if CHARGE_MAX_CURRENT is reduced
    4. Additionally we usually implement a BatteryProtection based on Cell Voltages etc. inside the battery implementation (at least for LFP batteries)
  3. Our implementations typically implement “StartStoppable” which allows handling STOP commands. E.g. if you stop the ESS, it will also stop the BATTERY.

Regards,
Stefan