Skip to content

Binding for Growatt SPH10000-TL3-BH-UP CAN protocol #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ErikssonPer opened this issue Dec 20, 2024 · 46 comments
Open

Binding for Growatt SPH10000-TL3-BH-UP CAN protocol #85

ErikssonPer opened this issue Dec 20, 2024 · 46 comments

Comments

@ErikssonPer
Copy link

Hi again,
I have a Growatt SPH10000-TL3-BH-UP and ARK bms with 4 modules.

I did a quick test setting the app up for PYLON_HV_CAN but that didn't work, inverter reported bms error.
So I've pulled some logs to try and figure out the protocol.

It seems growatt has went away from pylon protocol and made it's own, this is what I found so far.

Tomorrow i'll disconnect 1 module and run logs again with only 3 and see if I can find what changes.

Inverter sends this until the BMS responds
3010 8 0E DF 14 00 00 00 00 00
4200 8 02 00 00 00 00 00 00 E3
4200 8 00 00 00 00 00 00 00 E3
8210 8 AA 00 00 00 00 00 00 00
3010 8 0E E0 14 00 00 00 00 00
And so on.......
3010 byte 0 and 1 seem to be a counter beacuse it's always incrementing with 1, the rest never changes.

When BMS is powered up and responds for the first time inverter only sends this with 1 second interval, byte 0 and 1 still increments with 1.
3010 8 0E EF 14 00 00 00 00 00

BMS response look like this, ID's not matching anything I've seen and the data is arranged differently also.

(213,6V, no charge/discharge 24C SOC 100% SOH100%)

3020 [8] 00 00 00 00 00 00 00 00 Never changes
3030 [8] 18 0C 13 17 1C 17 00 01 Some type of counter, maybe Time and date?
3110 [8] 08 E0 00 00 00 FA 30 41 08E0 Max voltage 227.2 00FA 25A 00FA 25A Max discharge and charge
3120 [8] 00 00 00 00 00 00 00 00 Never changes
3130 [8] 08 58 00 00 00 F0 64 64 0848 =213,6V 0000 Charge/discharge current (Decimal from signed 2's complement )
00F0 24C 64 SOC 100% 64 SOH 100%
3140 [8] 13 4A 13 4C 47 54 01 28 0128 = 296 Number of cycles
3150 [8] 07 60 01 27 00 40 00 04 0760 never changes 0127 29,5 highest cell temp? 40 64 cells? 04 4 Modules?
3160 [8] 00 00 04 2D 01 18 00 DD 00DD 22.1 Lowest cell temp?
3170 [8] 01 03 04 0E 64 05 01 70
3180 [8] 00 00 00 01 00 40 00 41
3190 [8] 00 0D 12 0D 09 00 00 00
3200 [8] 00 00 02 00 00 00 0E 10
3220 [8] 00 00 00 00 00 00 00 02
3230 [8] 01 30 30 32 32 33 34 30
3240 [8] 01 04 DD B9 01 05 51 0B
3250 [8] 11 FF 11 FF 11 FF 11 FF Never changes
3260 [8] 00 00 00 00 00 00 00 00 Never changes
3270 [8] 00 00 00 00 00 00 00 00
3F00 [8] 00 00 00 00 00 00 00 00 Never changes

3110 BYTE 7
01 = Idle?
02 =Charging
03 =Discharge
41 = Balancing?
42 = fully charged?
61 = Initiating?
At startup shows 61 then 41 then 01 until charge or discharge begins
When fully charged shows 42 for a brief moment then 41

Growatt SPH inverter with ARK bms startup.txt

@ai-republic
Copy link
Owner

Yeah, that's not a protocol I've seen before. Have you tried to contact Growatt support and as for the CAN specification?

@ErikssonPer
Copy link
Author

Many have tried but they are extremly tight lipped.

@romanbetwo
Copy link

Let me fix that for you.

@romanbetwo
Copy link

Communication protocol of Growatt high voltage battery CAN V1.10 (3).pdf

@romanbetwo
Copy link

and bonus track > all possible errors
All error list EN.xlsx

@ErikssonPer
Copy link
Author

What kind of magic superpowers do you possess?
That's golden.

@romanbetwo
Copy link

Probably all kind of magic, but I still need to "kick" my self to start learning how CAN communication and translation works inclusing python and all that fancy stuff. I worked in R&D and testing equipment with all kind of brands. Equipment like IFR, Agilent, Yello, Keyence and many more. Whirpool, Asko, Gorenje, Arçelik, Candy, Bosch..

I work very closely with growatt engineering team since I start working for company that fix issues :)

@ErikssonPer
Copy link
Author

Do you have the low voltage protocol also, the version I have is half chinese half english?

@romanbetwo
Copy link

abra-ka-dabra
Communication protocol of Growatt low voltage battery CAN V1.04 (1).pdf

@ai-republic
Copy link
Owner

@romanbetwo sweet! I will check them out later and provide a new binding for the Growatt HV over the holidays

@ErikssonPer
Copy link
Author

It looks like both HV and LV protocols are more or less identical excapt they have changed the ID's, 311 to 3110, 312 to 3120 and so on.
It's a 2 fer 1 kinda deal.

In my case that might be beneficial since the emus G1 bms I have now have a setting to emulate growatt LV protocol.

I have to send another heartbeat command with ID 301 to start it but then it looks like it matches.
A short snippet from that looks like this,
image

The different heartbeats I think is due to emus following another version of the protocol.

@ai-republic
Copy link
Owner

@ErikssonPer, @romanbetwo FYI: I've implemented the Growatt HV and LV CAN bindings for inverter and BMS and are ready for further testing 😉

@ErikssonPer
Copy link
Author

@ai-republic
Downloaded the Configurator and ran the setup, no issues.

But when I started it the following happens,
jevlar@rpi:~/bms $ ./start.sh
2025-01-07 20:02:40.388 | INFO | main | til.SystemProperties:22 | Loading config.properties from: config/config.properties
2025-01-07 20:02:40.509 | DEBUG | main | ging.LoggerProviders:152 | Logging Provider: org.jboss.logging.Log4j2LoggerProvider
2025-01-07 20:02:42.981 | INFO | main | ore.InverterProducer:76 | Created inverter binding: GROWATT_HV_CAN
2025-01-07 20:02:43.102 | INFO | main | verter.core.Inverter:53 | Using plugins: []
Exception in thread "main" org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001480: Bean type class com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor is not proxyable because it contains a final method public final void com.airepublic.bmstoinverter.core.BMS.process(java.lang.Runnable) - <unknownjakarta.enterprise.inject.spi.Bean instance>.
at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:244)
at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:199)
at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:162)
at org.jboss.weld.bean.proxy.ClientProxyProvider.getClientProxy(ClientProxyProvider.java:238)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:678)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:666)
at org.jboss.weld.bean.builtin.InstanceImpl.getBeanInstance(InstanceImpl.java:262)
at org.jboss.weld.bean.builtin.InstanceImpl.get(InstanceImpl.java:114)
at com.airepublic.bmstoinverter.core.BMSListProducer.createBMS(BMSListProducer.java:94)
at com.airepublic.bmstoinverter.core.BMSListProducer.produceBMSList(BMSListProducer.java:80)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:95)
at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:85)
at org.jboss.weld.injection.producer.ProducerMethodProducer.produce(ProducerMethodProducer.java:103)
at org.jboss.weld.injection.producer.AbstractMemberProducer.produce(AbstractMemberProducer.java:161)
at org.jboss.weld.bean.AbstractProducerBean.create(AbstractProducerBean.java:180)
at org.jboss.weld.contexts.unbound.DependentContextImpl.get(DependentContextImpl.java:64)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:684)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:666)
at org.jboss.weld.manager.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:784)
at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:92)
at org.jboss.weld.util.Beans.injectBoundFields(Beans.java:345)
at org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:356)
at org.jboss.weld.injection.producer.ResourceInjector$1.proceed(ResourceInjector.java:69)
at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:48)
at org.jboss.weld.injection.producer.ResourceInjector.inject(ResourceInjector.java:71)
at org.jboss.weld.injection.producer.BasicInjectionTarget.inject(BasicInjectionTarget.java:117)
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:161)
at org.jboss.weld.contexts.AbstractContext.get(AbstractContext.java:96)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
at org.jboss.weld.bean.ContextualInstanceStrategy$ApplicationScopedContextualInstanceStrategy.get(ContextualInstanceStrategy.java:140)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:102)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:131)
at com.airepublic.bmstoinverter.BmsToInverter$Proxy$_$$_WeldClientProxy.start(Unknown Source)
at com.airepublic.bmstoinverter.BmsToInverter.main(BmsToInverter.java:88)
2025-01-07 20:02:43.125 | INFO | Thread-1 | verter.BmsToInverter:426 | Shutting down BMS and inverter threads...FAILED
2025-01-07 20:02:43.130 | INFO | Thread-1 | verter.BmsToInverter:458 | Shutting down ports...OK
Weld SE container 57ea3c97-126f-46f5-9ad7-0abadb3173a3 shut down by shutdown hook

@romanbetwo
Copy link

I will do the test tomorrow, but it looks like an issue

@ai-republic
Copy link
Owner

@ErikssonPer oh, thanks for finding that. It should be fixed now. Please Clean install again. Thanks!

@romanbetwo
Copy link

okay so , I've been playin arround and finaly figure out that .. i have bad HAT for this application.. 2xRS 1xCAN .. however I need 2xCAN...
anyway
I try to sim battery for Growatt HV CAN
Inverter does nothing.
settings:
bms none
inv growatt hv can > can0 > 500k 1

the log >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2025-01-08 17:21:47.118 | ERROR | Thread-3 | InverterCANProcessor:78 | Error creating send frames:
java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.StringLatin1.charAt(StringLatin1.java:48) ~[?:?]
at java.lang.String.charAt(String.java:1517) ~[?:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.sendBatteryCapacity(GrowattHVInverterCANProcessor.java:239) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.createSendFrames(GrowattHVInverterCANProcessor.java:64) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.core.Inverter.process(Inverter.java:177) ~[core-api-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$4(BmsToInverter.java:295) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]
at java.lang.Thread.run(Thread.java:840) [?:?]
2025-01-08 17:21:47.122 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:47.124 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0xC8, 0xFF, 0x38, 0x00, 0x00]

2025-01-08 17:21:47.127 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0xC8, 0xFF, 0x38, 0x00, 0x00]

2025-01-08 17:21:47.129 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:47.132 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-08 17:21:47.135 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-08 17:21:47.138 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:47.139 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x30, 0x08, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x00, 0xFA, 0x18, 0x64]

2025-01-08 17:21:47.141 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x30, 0x08, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x00, 0xFA, 0x18, 0x64]

2025-01-08 17:21:47.496 | INFO | Thread-2 | verter.BmsToInverter:268 | Reading BMS #1 NONE on none...
2025-01-08 17:21:47.498 | INFO | Thread-2 | verter.BmsToInverter:320 |
BMS SOC V A CellMinV CellMaxV CellDiff
#1 -0.1 0.0 0.0 0.0(#0) 0.0(#0) 0.0

2025-01-08 17:21:47.501 | INFO | Thread-2 | verter.BmsToInverter:390 | BMS alarms:
NONE
2025-01-08 17:21:48.143 | INFO | Thread-3 | verter.BmsToInverter:294 | Sending to inverter GROWATT_HV_CAN on can0...
2025-01-08 17:21:48.145 | DEBUG | Thread-3 | ocol.can.JavaCANPort:76 | CAN frame read...
2025-01-08 17:21:48.147 | DEBUG | Thread-3 | ocol.can.JavaCANPort:82 | CAN read frame Buffer (HEX): [0x00, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06]

2025-01-08 17:21:48.150 | DEBUG | Thread-3 | verter.core.Inverter:150 | Inverter GROWATT_HV_CAN received: Buffer (HEX): [0x00, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06]

2025-01-08 17:21:48.151 | DEBUG | Thread-3 | verter.core.Inverter:156 | Calling inverter plugin (onReceive): SimulatedBatteryPackPlugin
2025-01-08 17:21:48.154 | DEBUG | Thread-3 | verter.core.Inverter:160 | Inverter GROWATT_HV_CAN received (after running plugins): Buffer (HEX): [0x00, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06]

2025-01-08 17:21:48.156 | DEBUG | Thread-3 | verter.core.Inverter:171 | Calling inverter plugin (onBatteryAggregation): SimulatedBatteryPackPlugin
2025-01-08 17:21:48.160 | DEBUG | Thread-3 | InverterCANProcessor:142 | Sending max/min charge and discharge voltage and current limits: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0xC8, 0xFF, 0x38, 0x00, 0x00]

2025-01-08 17:21:48.163 | DEBUG | Thread-3 | InverterCANProcessor:205 | Sending alarms: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-08 17:21:48.166 | DEBUG | Thread-3 | InverterCANProcessor:225 | Sending battery status: Buffer (HEX): [0x00, 0x00, 0x31, 0x30, 0x08, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x00, 0xFA, 0x18, 0x64]

2025-01-08 17:21:48.169 | ERROR | Thread-3 | InverterCANProcessor:78 | Error creating send frames:
java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.StringLatin1.charAt(StringLatin1.java:48) ~[?:?]
at java.lang.String.charAt(String.java:1517) ~[?:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.sendBatteryCapacity(GrowattHVInverterCANProcessor.java:239) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.createSendFrames(GrowattHVInverterCANProcessor.java:64) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.core.Inverter.process(Inverter.java:177) ~[core-api-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$4(BmsToInverter.java:295) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]
at java.lang.Thread.run(Thread.java:840) [?:?]
2025-01-08 17:21:48.172 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:48.175 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0xC8, 0xFF, 0x38, 0x00, 0x00]

2025-01-08 17:21:48.178 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0xC8, 0xFF, 0x38, 0x00, 0x00]

2025-01-08 17:21:48.179 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:48.182 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-08 17:21:48.185 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-08 17:21:48.187 | DEBUG | Thread-3 | verter.core.Inverter:188 | Calling inverter plugin (onSend): SimulatedBatteryPackPlugin
2025-01-08 17:21:48.189 | DEBUG | Thread-3 | verter.core.Inverter:193 | Inverter GROWATT_HV_CAN send: Buffer (HEX): [0x00, 0x00, 0x31, 0x30, 0x08, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x00, 0xFA, 0x18, 0x64]

2025-01-08 17:21:48.192 | DEBUG | Thread-3 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x30, 0x08, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x00, 0xFA, 0x18, 0x64]

^C2025-01-08 17:21:48.476 | INFO | Thread-1 | verter.BmsToInverter:426 | Shutting down BMS and inverter threads...FAILED
2025-01-08 17:21:48.479 | INFO | Thread-1 | ocol.can.JavaCANPort:127 | Shutting down port 'can0'...OK
2025-01-08 17:21:48.480 | INFO | Thread-1 | verter.BmsToInverter:458 | Shutting down ports...OK
Weld SE container 39c02918-e524-4da4-a048-1f6f009f117c shut down by shutdown hook

Different storry

If I set for pylon -HV CAN it start to charge battery ( i know its dangerous but I am okay with that)

end of storry

Another try > SPH CAN > Batt can > parallel CAN dongle >

For some resason I was told that my battery should have Pylon HV can but I am not able to read much from it.... When I connect battery CAN > SPH CAN direct I am able to finaly scan some data with USB>CAN.. which does not look like specs ...
i will include the *doc

data: >>>>>>>
NO Direction Time Scale Frame Type Frame Format Frame ID Length Data
0 Receive 16:19:19:076 Data frame Extended frame 00008200 8 aa 00 00 00 00 00 00 00
1 Receive 16:19:19:107 Data frame Extended frame 00004200 8 02 00 00 00 00 00 00 e8
2 Receive 16:19:19:107 Data frame Extended frame 00004200 8 00 00 00 00 00 00 00 e8
3 Receive 16:19:19:123 Data frame Extended frame 00004210 8 3f 08 30 75 92 04 18 64
4 Receive 16:19:19:138 Data frame Extended frame 00004220 8 2d 09 00 07 24 77 24 77
5 Receive 16:19:19:154 Data frame Extended frame 00004230 8 e4 0c df 0c 0e 00 08 00
6 Receive 16:19:19:170 Data frame Extended frame 00004240 8 a6 04 88 04 03 00 19 00
7 Receive 16:19:19:185 Data frame Extended frame 00004250 8 03 14 00 00 00 00 00 00
8 Receive 16:19:19:201 Data frame Extended frame 00004260 8 20 ce 18 ce 04 00 01 00
9 Receive 16:19:19:201 Data frame Extended frame 00004270 8 a6 04 88 04 01 00 04 00
10 Receive 16:19:19:217 Data frame Extended frame 00004280 8 00 00 00 00 00 00 00 00
11 Receive 16:19:19:248 Data frame Extended frame 00004290 8 00 00 00 00 00 00 00 00
12 Receive 16:19:19:248 Data frame Extended frame 000042e0 8 41 53 48 48 45 53 53 28
13 Receive 16:19:19:263 Data frame Extended frame 000042f0 8 41 53 47 4f 46 54 ff ff
14 Receive 16:19:19:279 Data frame Extended frame 00007310 8 01 00 02 01 01 02 00 00
15 Receive 16:19:19:295 Data frame Extended frame 00007320 8 40 00 04 10 cd 00 64 00
16 Receive 16:19:19:310 Data frame Extended frame 00004200 8 00 00 00 00 00 00 00 e8
17 Receive 16:19:19:342 Data frame Extended frame 00004210 8 3f 08 30 75 92 04 18 64
18 Receive 16:19:19:357 Data frame Extended frame 00004220 8 2d 09 00 07 24 77 24 77
19 Receive 16:19:19:373 Data frame Extended frame 00004230 8 e4 0c df 0c 0e 00 08 00
20 Receive 16:19:19:389 Data frame Extended frame 00004240 8 a6 04 88 04 03 00 19 00
21 Receive 16:19:19:404 Data frame Extended frame 00004250 8 03 14 00 00 00 00 00 00
22 Receive 16:19:19:420 Data frame Extended frame 00004260 8 20 ce 16 ce 04 00 01 00
23 Receive 16:19:19:451 Data frame Extended frame 00004270 8 a6 04 88 04 01 00 04 00
24 Receive 16:19:19:467 Data frame Extended frame 00004280 8 00 00 00 00 00 00 00 00
25 Receive 16:19:19:482 Data frame Extended frame 00004290 8 00 00 00 00 00 00 00 00
26 Receive 16:19:19:498 Data frame Extended frame 000042e0 8 41 53 48 48 45 53 53 28
27 Receive 16:19:19:514 Data frame Extended frame 000042f0 8 41 53 47 4f 46 54 ff ff
28 Receive 16:19:19:826 Data frame Extended frame 00008200 8 aa 00 00 00 00 00 00 00
29 Receive 16:19:19:857 Data frame Extended frame 00008200 8 aa 00 00 00 00 00 00 00
30 Receive 16:19:19:873 Data frame Extended frame 00004200 8 02 00 00 00 00 00 00 e8
31 Receive 16:19:19:889 Data frame Extended frame 00007310 8 01 00 02 01 01 02 00 00
32 Receive 16:19:19:904 Data frame Extended frame 00007320 8 40 00 04 10 cd 00 64 00
etc etc

With this configuration:
Battery shows correct SOC but inverter is pretty much confused,.. like realy confused .. start charging and sh+t with no agreements on set parameters or settings ...so pretty heavy to game play&fxxk arround to find out :D.

todo: get a 2x can hat /current is usable for MOD or huawei
We are missing something in growatt HV plugin
I will create new topic for "my battery"
If I missed something let me know
bms_ems_v01_dbc.xlsx

@ErikssonPer
Copy link
Author

Ran a quick test with it connected inbetween the inverter on can0 and battery on can1.

The heartbeat message that's sent out on can1 to the bms looks like this,
00003111 8 00 00 00 00 00 00 00 00

So the battery won't respond with any data.

It looks like an error is reported in the log.
BMS-to-Inverter.log

@ai-republic
Copy link
Owner

So I'll try to answer one by one 😉

  1. I fixed the IndexOutOfBoundsException so you can try the simulated battery plugin if you like
  2. The CAN data you captured definitely matches the PYLON_HV_CAN or SOLIS_HV_CAN
  3. In the log file I see that the port was not initialized properly (sometimes happens on the PI). If you see this - and you're sure it configured properly - just try to reboot it (a few times).

PS: When doing tests please disable the webserver as it makes the log file hard to read 😉

@romanbetwo
Copy link

Will do sir 🫡

@ErikssonPer
Copy link
Author

ErikssonPer commented Jan 18, 2025

I'm not having any luck,
It works fine doing cansend or candump on both channels, data is recieved or sent as expected.

If I start the App it wont send anything out on either.

Extract from log,

2025-01-18 18:22:46.010 | INFO | main | til.SystemProperties:22 | Loading config.properties from: config/config.properties
2025-01-18 18:22:48.106 | INFO | main | ore.InverterProducer:76 | Created inverter binding: GROWATT_HV_CAN
2025-01-18 18:22:48.249 | INFO | main | verter.core.Inverter:53 | Using plugins: []
2025-01-18 18:22:48.331 | INFO | main | core.BMSListProducer:105 | Intialized BMS #1[GROWATT_HV_CAN] on port can1
2025-01-18 18:22:48.357 | INFO | main | verter.BmsToInverter:261 | Starting BMS receiver...
2025-01-18 18:22:48.369 | INFO | Thread-2 | verter.BmsToInverter:268 | Reading BMS #1 GROWATT_HV_CAN on can1...
2025-01-18 18:22:48.379 | INFO | Thread-2 | toinverter.core.Port:111 | Opening can1 ...
2025-01-18 18:22:48.497 | INFO | Thread-2 | toinverter.core.Port:113 | Opening port can1 SUCCESSFUL
2025-01-18 18:22:49.544 | ERROR | Thread-2 | stoinverter.core.BMS:192 | Error requesting data!
tel.schich.javacan.platform.linux.LinuxNativeOperationException: Unable to read from the socket - errorNumber=11, errorMessage='Resursen tillfälligt otillgänglig'
at tel.schich.javacan.SocketCAN.read(Native Method) ~[javacan-core-3.2.4.jar:?]
at tel.schich.javacan.AbstractCanChannel.readSocket(AbstractCanChannel.java:213) ~[javacan-core-3.2.4.jar:?]
at tel.schich.javacan.RawCanChannelImpl.readUnsafe(RawCanChannelImpl.java:85) ~[javacan-core-3.2.4.jar:?]
at tel.schich.javacan.RawCanChannelImpl.read(RawCanChannelImpl.java:79) ~[javacan-core-3.2.4.jar:?]
at tel.schich.javacan.RawCanChannelImpl.read(RawCanChannelImpl.java:74) ~[javacan-core-3.2.4.jar:?]
at com.airepublic.bmstoinverter.protocol.can.JavaCANPort.receiveFrame(JavaCANPort.java:77) ~[protocol-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.sendMessage(GrowattHVBmsCANProcessor.java:120) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.collectData(GrowattHVBmsCANProcessor.java:104) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.core.BMS.process(BMS.java:173) ~[core-api-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$2(BmsToInverter.java:269) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]
at java.lang.Thread.run(Thread.java:1570) [?:?]
2025-01-18 18:22:50.574 | INFO | Thread-2 | verter.BmsToInverter:268 | Reading BMS #1 GROWATT_HV_CAN on can1...

@ai-republic
Copy link
Owner

hmm, it looks like its something with your CAN configuration for your CAN adapter is not correctly set up. Or its not (yet) started properly. The error message comes straight from the SocketCAN unix module.

@ErikssonPer
Copy link
Author

Did a new test today, setup as BMS on CAN1 and inverter on CAN0
The app sends out a CAN message with id 3111 on CAN1, I guess that's supposed to be the heartbeat/wakeup but that should be 3010 so maybe a typo in the code.

Data sent out on CAN1 with 1 second interval
0 00003111 X 8 00 00 00 00 00 00 00 0

So it is able to send but fails to read.

Log,

./start.sh2025-01-20 22:31:02.490 | INFO  | main       | til.SystemProperties:22    | Loading config.properties from: config/config.properties2025-01-20 22:31:02.574 | DEBUG | main       | ging.LoggerProviders:152   | Logging Provider: org.jboss.logging.Log4j2LoggerProvider2025-01-20 22:31:04.504 | INFO  | main       | ore.InverterProducer:76    | Created inverter binding: GROWATT_HV_CAN2025-01-20 22:31:04.612 | INFO  | main       | verter.core.Inverter:53    | Using plugins: []2025-01-20 22:31:04.668 | INFO  | main       | core.BMSListProducer:105   | Intialized BMS #1[GROWATT_HV_CAN] on port can12025-01-20 22:31:04.687 | INFO  | main       | verter.BmsToInverter:261   | Starting BMS receiver...2025-01-20 22:31:04.692 | INFO  | Thread-2   | verter.BmsToInverter:268   | Reading BMS #1 GROWATT_HV_CAN on can1...2025-01-20 22:31:04.696 | INFO  | Thread-2   | toinverter.core.Port:111   | Opening can1 ...2025-01-20 22:31:04.748 | INFO  | Thread-2   | toinverter.core.Port:113   | Opening port can1 SUCCESSFUL2025-01-20 22:31:04.753 | DEBUG | Thread-2   | attHVBmsCANProcessor:115   | SEND: Buffer (HEX): [0x00, 0x00, 0x31, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2025-01-20 22:31:04.757 | DEBUG | Thread-2   | ocol.can.JavaCANPort:115   | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2025-01-20 22:31:04.762 | DEBUG | Thread-2   | ocol.can.JavaCANPort:76    | CAN frame read...2025-01-20 22:31:05.790 | ERROR | Thread-2   | stoinverter.core.BMS:192   | Error requesting data!tel.schich.javacan.platform.linux.LinuxNativeOperationException: Unable to read from the socket - errorNumber=11, errorMessage='Resource temporarily unavailable'        at tel.schich.javacan.SocketCAN.read(Native Method) ~[javacan-core-3.2.4.jar:?]        at tel.schich.javacan.AbstractCanChannel.readSocket(AbstractCanChannel.java:213) ~[javacan-core-3.2.4.jar:?]        at tel.schich.javacan.RawCanChannelImpl.readUnsafe(RawCanChannelImpl.java:85) ~[javacan-core-3.2.4.jar:?]        at tel.schich.javacan.RawCanChannelImpl.read(RawCanChannelImpl.java:79) ~[javacan-core-3.2.4.jar:?]        at tel.schich.javacan.RawCanChannelImpl.read(RawCanChannelImpl.java:74) ~[javacan-core-3.2.4.jar:?]        at com.airepublic.bmstoinverter.protocol.can.JavaCANPort.receiveFrame(JavaCANPort.java:77) ~[protocol-can-0.0.1-SNAPSHOT.jar:?]        at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.sendMessage(GrowattHVBmsCANProcessor.java:120) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]        at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.collectData(GrowattHVBmsCANProcessor.java:104) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]        at com.airepublic.bmstoinverter.core.BMS.process(BMS.java:173) ~[core-api-0.0.1-SNAPSHOT.jar:?]        at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]        at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$2(BmsToInverter.java:269) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]        at java.lang.Thread.run(Thread.java:1570) [?:?]2025-01-20 22:31:06.817 | INFO  | Thread-2   | verter.BmsToInverter:268   | Reading BMS #1 GROWATT_HV_CAN on can1...2025-01-20 22:31:06.819 | DEBUG | Thread-2   | attHVBmsCANProcessor:115   | SEND: Buffer (HEX): [0x00, 0x00, 0x31, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

Ifconfig while app is running shows both can ports active
$ ifconfig
can0: flags=193<UP,RUNNING,NOARP> mtu 72
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 65536 (UNSPEC)
RX packets 72 bytes 544 (544.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 17 bytes 104 (104.0 B)
TX errors 1710 dropped 4 overruns 0 carrier 4 collisions 0
device interrupt 57

can1: flags=193<UP,RUNNING,NOARP> mtu 72
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 65536 (UNSPEC)
RX packets 72 bytes 544 (544.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 55 bytes 440 (440.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 58

When testing with a short simple python script both can0 and can1 work for both send and recieve.

@ai-republic
Copy link
Owner

This part is the crucial part:
2025-01-20 22:31:05.790 | ERROR | Thread-2 | stoinverter.core.BMS:192 | Error requesting data!tel.schich.javacan.platform.linux.LinuxNativeOperationException: Unable to read from the socket - errorNumber=11, errorMessage='Resource temporarily unavailable' at tel.schich.javacan.SocketCAN.read(Native Method) ~[javacan-core-3.2.4.jar:?]

This implies that the socket it not available. So either in use, not initialized yet, or not configured correctly.
Is your adapter using the SocketCAN library or something else?

@ErikssonPer
Copy link
Author

It's a waveshare 2 channel fd can hat

Can't figure it out, everything seems to check out and I can send and recieve on both channels using command line or a simple python script.

And the app is able to send

@ErikssonPer
Copy link
Author

Gonna try to use it in legacy mode and see what that does.

@ai-republic
Copy link
Owner

Maybe also try to re-install the Waveshare hat on a fresh Raspian OS installation and reconfigure it without adding any other libraries like the python scripts etc.
Another thing that comes to mind, did you set the baudrate properly for the BMS and CAN port?

@ErikssonPer
Copy link
Author

Both channels are set to 500kbit and I can log data being sent from both the inverter and bms with candump so it's correct.

I noticed something today, for fun I ran the configurator again and set it to pylon hv bms and growatt hv inverter.

With those settings it sends out a different heartbeat to the bms, (ID 4200) which is correct for pylon protocol.
Image

Remember it sends this when setup as growatt_hv:
0 00003111 X 8 00 00 00 00 00 00 00 0
There's no ID like that in the growatt protocol.

But it doesn't show any errors in the log now,

jevlar@rpi:~ $ ./start.sh
2025-01-29 20:05:56.961 | INFO | main | til.SystemProperties:22 | Loading config.properties from: config/config.properties
2025-01-29 20:05:57.057 | DEBUG | main | ging.LoggerProviders:152 | Logging Provider: org.jboss.logging.Log4j2LoggerProvider
2025-01-29 20:05:58.992 | INFO | main | ore.InverterProducer:76 | Created inverter binding: GROWATT_HV_CAN
2025-01-29 20:05:59.113 | INFO | main | verter.core.Inverter:53 | Using plugins: []
2025-01-29 20:05:59.141 | INFO | main | core.BMSListProducer:105 | Intialized BMS #1[PYLON_HV_CAN] on port can0
2025-01-29 20:05:59.170 | INFO | main | verter.BmsToInverter:261 | Starting BMS receiver...
2025-01-29 20:05:59.177 | INFO | Thread-2 | verter.BmsToInverter:268 | Reading BMS #1 PYLON_HV_CAN on can0...
2025-01-29 20:05:59.180 | INFO | Thread-2 | toinverter.core.Port:111 | Opening can0 ...
2025-01-29 20:05:59.256 | INFO | Thread-2 | toinverter.core.Port:113 | Opening port can0 SUCCESSFUL
2025-01-29 20:05:59.269 | DEBUG | Thread-2 | lonHVBmsCANProcessor:58 | SEND: Buffer (HEX): [0x00, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-29 20:05:59.272 | DEBUG | Thread-2 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-01-29 20:05:59.277 | DEBUG | Thread-2 | ocol.can.JavaCANPort:76 | CAN frame read...
2025-01-29 20:06:00.282 | INFO | Thread-2 | verter.BmsToInverter:320 |
BMS SOC V A CellMinV CellMaxV CellDiff

2025-01-29 20:06:00.282 | INFO | main | verter.BmsToInverter:290 | Starting inverter sender...
2025-01-29 20:06:00.283 | INFO | Thread-2 | verter.BmsToInverter:390 | BMS alarms:
NONE
2025-01-29 20:06:00.286 | INFO | Thread-3 | verter.BmsToInverter:294 | Sending to inverter GROWATT_HV_CAN on can1...
2025-01-29 20:06:00.288 | DEBUG | Thread-3 | verter.core.Inverter:207 | No battery data yet received to send to inverter GROWATT_HV_CAN!
2025-01-29 20:06:01.285 | INFO | Thread-2 | verter.BmsToInverter:268 | Reading BMS #1 PYLON_HV_CAN on can0...

Could this be a clue?

@ai-republic
Copy link
Owner

I don't get who sends the 0x3111 ID? Neither the PYLON_HV_CAN nor the GROWATT_HV_CAN bindings send these IDs

@ErikssonPer
Copy link
Author

ErikssonPer commented Feb 2, 2025

Trust me, it's sent with a 1 second interval as soon as I start the app with it setup for Growatt hv BMS
I tested without anything else connected to the can so it's for sure the app.

22:31:04.668 | INFO | main | core.BMSListProducer:105 | Intialized BMS #1[GROWATT_HV_CAN] on port can1
2025-01-20 22:31:04.757 | DEBUG | Thread-2 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

@cmax1-gmx
Copy link

cmax1-gmx commented Feb 7, 2025

Good evening,
My System is a Growatt SPH10000-TL3-BH-UP and Battery ARK HV with 3 modules.
I'd like to get a better insight in the battery system, so no need to intercept the Traffic from and to the inverter - I just want to read the info flying by.

So config is Growatt_HV_CAN for BMS, NONE for Inverter. Using that with Log-Level Info as is default it looked good, no error in the log - but no data visible via Web-Server.

Setting Log-Level to Debug revealed the following Problem:


2025-02-07 17:16:10.852 | INFO  | Thread-10  | verter.BmsToInverter:268   | Reading BMS #0 GROWATT_HV_CAN on can0...
2025-02-07 17:16:10.853 | DEBUG | Thread-10  | attHVBmsCANProcessor:115   | SEND: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-07 17:16:10.854 | DEBUG | Thread-10  | ocol.can.JavaCANPort:115   | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-07 17:16:10.855 | DEBUG | Thread-10  | ocol.can.JavaCANPort:76    | CAN frame read...
2025-02-07 17:16:10.856 | DEBUG | Thread-10  | ocol.can.JavaCANPort:82    | CAN read frame Buffer (HEX): [0x10, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0xA8, 0x00, 0xFA, 0x00, 0xFA, 0x30, 0x01]

2025-02-07 17:16:10.857 | DEBUG | Thread-10  | attHVBmsCANProcessor:121   | RECEIVED: Buffer (HEX): [0x10, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0xA8, 0x00, 0xFA, 0x00, 0xFA, 0x30, 0x01]

2025-02-07 17:16:10.857 | ERROR | Thread-10  | stoinverter.core.BMS:192   | Error requesting data!
java.lang.NullPointerException: Cannot invoke "com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor$Command.ordinal()" because "command" is null
	at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.sendMessage(GrowattHVBmsCANProcessor.java:160) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
	at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor.collectData(GrowattHVBmsCANProcessor.java:104) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
	at com.airepublic.bmstoinverter.core.BMS.process(BMS.java:173) ~[core-api-0.0.1-SNAPSHOT.jar:?]
	at com.airepublic.bmstoinverter.bms.growatthv.can.GrowattHVBmsCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[bms-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
	at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$2(BmsToInverter.java:269) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]
	at java.lang.Thread.run(Thread.java:840) [?:?]

Do you have an idea what could be wrong there ?

BTW, I've not seen other errors so far, just the lines above repeating for every received frame, regardless what ID the frames have (if you need full log I can provide it)

Thank you for you great work!

@ai-republic
Copy link
Owner

@cmax1-gmx I fixed the NPE. Please let me know if it works for you and also please attach the log file again. I'm curious what command you receive that is not mapped

@ai-republic
Copy link
Owner

ai-republic commented Feb 8, 2025

Trust me, it's sent with a 1 second interval as soon as I start the app with it setup for Growatt hv BMS I tested without anything else connected to the can so it's for sure the app.

22:31:04.668 | INFO | main | core.BMSListProducer:105 | Intialized BMS #1[GROWATT_HV_CAN] on port can1 2025-01-20 22:31:04.757 | DEBUG | Thread-2 | ocol.can.JavaCANPort:115 | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

@ErikssonPer I had a look again at the code. Yes, it will send out the 0x3111 to communicate with the second BMS.
So the logic as per spec is

  • 0x3110 for BMS 1 (ID 0)
  • 0x3111 for BMS 2 (ID 1)

Could you try to configure your BMS ID to 0 please?

@cmax1-gmx
Copy link

Looks better, but still a problem:

2025-02-08 10:14:57.091 | INFO  | Thread-10  | verter.BmsToInverter:268   | Reading BMS #0 GROWATT_HV_CAN on can0...
2025-02-08 10:14:57.094 | DEBUG | Thread-10  | attHVBmsCANProcessor:115   | SEND: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.096 | DEBUG | Thread-10  | ocol.can.JavaCANPort:115   | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.098 | DEBUG | Thread-10  | ocol.can.JavaCANPort:76    | CAN frame read...
2025-02-08 10:14:57.101 | DEBUG | Thread-10  | ocol.can.JavaCANPort:82    | CAN read frame Buffer (HEX): [0x20, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.103 | DEBUG | Thread-10  | attHVBmsCANProcessor:121   | RECEIVED: Buffer (HEX): [0x20, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.107 | WARN  | Thread-10  | attHVBmsCANProcessor:219   | Message could not be interpreted Buffer (HEX): [0x20, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.110 | DEBUG | Thread-10  | attHVBmsCANProcessor:115   | SEND: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.112 | DEBUG | Thread-10  | ocol.can.JavaCANPort:115   | CAN frame sending: Buffer (HEX): [0x00, 0x00, 0x31, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.115 | DEBUG | Thread-10  | ocol.can.JavaCANPort:76    | CAN frame read...
2025-02-08 10:14:57.117 | DEBUG | Thread-10  | ocol.can.JavaCANPort:82    | CAN read frame Buffer (HEX): [0x10, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0x8B, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.120 | DEBUG | Thread-10  | attHVBmsCANProcessor:121   | RECEIVED: Buffer (HEX): [0x10, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0x8B, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]

2025-02-08 10:14:57.122 | WARN  | Thread-10  | attHVBmsCANProcessor:219   | Message could not be interpreted Buffer (HEX): [0x10, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0x8B, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]

as before the result for all IDs is identical.

This is what is logged at the end of one cycle:

2025-02-08 10:14:56.087 | INFO  | Thread-10  | verter.BmsToInverter:320   |
BMS     SOC       V       A      CellMinV        CellMaxV       CellDiff
#1       -0.1   0.0     0.0     0.0(#0)         0.0(#0) 0.0

2025-02-08 10:14:56.089 | INFO  | Thread-10  | verter.BmsToInverter:390   | BMS alarms:
        NONE
2025-02-08 10:14:56.875 | INFO  | Thread-11  | verter.BmsToInverter:294   | Sending to inverter NONE on can1...

IDs seen: 0x3010 0x3020 0x3030 0x3110 0x3120 0x3130 0x3140 0x3150 0x3160 0x3170 0x3180 0x3190 0x3200 0x3220 0x3230 0x3240 0x3250 0x3260 0x3270 0x3280 0x3F00

Full Log:
BMS-to-Inverter.log

@cmax1-gmx
Copy link

cmax1-gmx commented Feb 8, 2025

an update: it seems that the problem is in line 151 in File GrowattHVBmsCANProcessor.java

final Command command = Command.forCommand(canId - 0x00001000);

After changing that to

final Command command = Command.forCommand(canId);

I get correct results (at least these look good to me) for most of the defined CAN IDs with exception of 0x3110, 0x3160 and 0x3170:

0x3110 - BufferUnderflowException
0x3160 - IndexOutOfBoundsException
0x3170 - IndexOutOfBoundsException

For details see attached partial Log (I've added Debug-Log-Enttries for the processed Command too):

BMS-to-Inverter-part.log

The other IDs that I've seen as listed in my post above are not processed at the moment as they are not defined.

I hope my infos can help - I've only very basic java-skills so I'm not able to do more then trying to help identifying the problem.

@ai-republic
Copy link
Owner

@cmax1-gmx , @ErikssonPer,
Thanks a lot for the logs. That really helped to fix the issues quickly!
I've updated the code so please try a Clean install and test again.

The issue with the initial readings of 0x3010-0x3030 I also covered 😄

@cmax1-gmx
Copy link

@ai-republic - have you overlooked my comment above related to the problem in File GrowattHVBmsCANProcessor.java or was it intentionally not to change that ?

153c153
<                     final Command command = Command.forCommand(canId - 0x00001000);
---
>                     final Command command = Command.forCommand(canId);

Without that change I did not get any message parsed.

Otherwise good news - no more exceptions thrown, the IDs defined are parsed. Some more comments about the values received:

Looking at the Line printed in the log

BMS     SOC       V       A         CellMinV          CellMaxV         CellDiff
#1       97.0   1459.8  -460.9  59.148(#47)     63.244(#3)      4.096

it is obvious that the values are not correct (LiFePo Cells have a Voltage of ~3.2V, my Battery with three blocks should have ~150 to 160V. This is a Byte-Order-Problem, converting the values above to Big-Endian gives the following:

BMS     SOC       V       A      CellMinV        CellMaxV       CellDiff
#1        97	159,3  -1,9.  3,321 (#47)    3,343 (#3)     0,022

Some of the other parsed IDs have additional small errors respectively few missing values. If needed I can provide details on that. Sometimes it ist difficult to get the right info out of the Growatt-Protocol-PDF (naming is misleading, wrong explications etc. - so for example for ID 0x3030 they mention that Time is epoch - that is completely wrong, each part of the date is just converted to hex, e.g. Year = 19, Month = 02, Day = 0A etc.)

I noticed that each time when the programm is started my inverter restarted too (Growatt's 5 Mins Startup Check). I suppose the app is sending out each received frame, not taking into account that I have configured "Inverter: NONE". After commenting out the send command no more restart, so perhaps you could take that into consideration (not sending anything when inverter is NONE - the dummy inverter does not send frames, but the BMS-Code does when NONE-Inverter is configured).

@romanbetwo
Copy link

Finaly getting back to life ,.. just joking still no time at all ..
SPH with pylon HV battery (like)

BMS-to-Inverter.log

2025-02-12 15:37:58.095 | ERROR | Thread-4 | InverterCANProcessor:78 | Error creating send frames:
java.lang.StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.StringLatin1.charAt(StringLatin1.java:48) ~[?:?]
at java.lang.String.charAt(String.java:1517) ~[?:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.sendManufacturerAndMaxCellVoltage(GrowattHVInverterCANProcessor.java:394) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor.createSendFrames(GrowattHVInverterCANProcessor.java:76) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.core.Inverter.process(Inverter.java:177) ~[core-api-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor$Proxy$_$$_WeldClientProxy.process(Unknown Source) ~[inverter-growatt-hv-can-0.0.1-SNAPSHOT.jar:?]
at com.airepublic.bmstoinverter.BmsToInverter.lambda$start$5(BmsToInverter.java:317) ~[bms-to-inverter-main-0.0.1-SNAPSHOT.jar:?]
at java.lang.Thread.run(Thread.java:840) [?:?]

this is probably last issue preventing to "run"

log>>

cheers
Roman

@cmax1-gmx
Copy link

@romanbetwo
do you happen to have a recent version of the "Growatt Inverter Modbus RTU Protocol", the version I've found via Google is 1.24 also called "latest", which dates 2020-04-28. There are a number of values which are clearly incorrect, so I suppose there have been changes since then ?

I'd like to compare what I can get via canbus vs modbus.

@romanbetwo
Copy link

Hi I'll request for latest and let you know.

@cmax1-gmx
Copy link

Thanks a lot !

@ai-republic
Copy link
Owner

ai-republic commented Feb 15, 2025

@cmax1-gmx , I removed the response mask and changed the frame to big endian. Let's see if you can get some correct values now! 😄
Also fixed the IndexOutOfBoundsException for the inverter binding

@romanbetwo
Copy link

@cmax1-gmx still no answer from growatt about latest and "greatest" modbus document .. they are so lazy after new year :D

@ai-republic I am still playing arround with SPH and pylon HV battery, Last issue seems to be gone but I do believe there is anotheone seems that pylon HV see 2#BMS

I want to continue in this threat, because its SPH related even if other part of build can be a problem.

2 logs >
solo BMS
and with the inverter

SPH shows that battery is OPEN, which means there is 0 voltage on terminals which is probably just a data from 2nd BMS.

bms_only_pylon HV.log

BMS-to-Inverter 17.2.log

@cmax1-gmx
Copy link

cmax1-gmx commented Feb 19, 2025

@ai-republic changing the whole frame to big endian is problematic - that changes the CAN ID too and decoding does not work any more.

To test I just moved that command further down

153                } else {
154                    frameReceived = true;
155                    // request has 4th byte 0x10 and response 0x20
156                    final Command command = Command.forCommand(canId);
-->                    receiveFrame.order(ByteOrder.BIG_ENDIAN);
157                    // move position to the data part
158                    receiveFrame.getInt();

to see if it would work - and it does. But I think a cleaner solution would be to define a buffer for just the data part of the can-frame (the 8 Bytes at the end).

To check the results I compiled a table to compare my manual decoding of the frames for IDs 3110-3200 coming out of my system using the Protocol-PDF from above with the values spit out from bms-to-inverter - see attached file.

Growatt-HV-CAN-Mappings.ods

@ai-republic
Copy link
Owner

Thanks @cmax1-gmx I will have a look at it. Very busy at the moment and currently suffering from the flu

@ai-republic
Copy link
Owner

@cmax1-gmx I moved the setting to big endian like you suggested. I hope it works 😉
Its strange to use two encodings (little and big endian) in one frame though..... 🤔

@cmax1-gmx
Copy link

cmax1-gmx commented Mar 4, 2025

@cmax1-gmx I moved the setting to big endian like you suggested. I hope it works 😉 I

Yes, it does - Thank you !

Its strange to use two encodings (little and big endian) in one frame though..... 🤔

Digging a bit deeper I found the following:

  • The whole frame as it is received from the net is big endian (as is default for network data). Byte-Order for CAN-Bus Data can be either big or little endian, depends on the implementation, so the CAN-BUS Controller (receiver) needs to take care of this.
  • without specifying big or little endian when fetching the data in a buffer by default system byte order is used - which is little endian for most systems
  • Growatt uses big endian (see Protocol-PDF) for high and low volt systems - as opposed to many others for example pylon, byd and other vendors

I think a possible way to adress that could be by defining the CAN-Bus Byte Order as a Config-Value and taking care of the byte order for the receiving buffer once directly in JavaCANPort.java when reading the frame, that could make it easier to add new Devices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants