Olen / solar-monitor

GNU General Public License v3.0
54 stars 21 forks source link

Plugin for Junctek KH140F bluetooth battery monitor #29

Open chriskomus opened 1 year ago

chriskomus commented 1 year ago

Hey, first off, thanks for this project!

I'm working on writing a plugin for the Junctek KH140F bluetooth battery shunt and monitor. I've gotten as far as getting characteristic data back, and I can find usable information within the values. However, I have no experience with this, so I'm a bit lost on how to parse the incoming stream of continuous values to get what I'm looking for at the right position.

Below are a bunch of matched values I've found with characteristic data. Some of them have the byte length in brackets.

As you can see, the data is in there! But the byte length and position of desired information is all over the place. The best option at this point is to pull bytes before the hex values that seem to consistently come afterwards. ie: since C0 comes after volt value, I could get 12.04v from 0XBB1204C00240D883EE ?

volts:

these all seem to start right after the BB, with C0 immediately after the volt value 12.04V - 0XBB1204C00240D883EE (9), 0XBB1204C00481D850EE (9) 12.05V - 0XBB1205C00241D885EE (9),0XBB1205C00241D885EE (9), 0XBB1205C002EE (6) 12.06V - 0XBB1206C020C10241D811EE (11), 0XBB1206C050C10603D801EE (11) 12.07V - 0XBB1207C09163D6022320D746EE (13) 12.32V - 0XBB1232C047EE,0XBB1232C050C10616D864EE 12.30V - 0XBB1230C020C10246D858EE, 0XBB1230C00246D833EE, 0XBB1230C045EE, 0XBB1230C00492D811EE

watts:

position is inconsistent, but D8 always follows the watt value 2.46W - 0XBB1230C020C10246D858EE,0XBB20C10246D800EE, 0XBB20C10246D800EE 1.23W - 0XBB10C10123D848EE 4.92W - 0XBB40C10492D810EE, 0XBB40C16437D6027500D70492D813EE 4.84W - 0XBB1210C00484D865EE, 0XBB1210C00484D865EE, 0XBB1210C00484D865EE 2.41W - 0XBB20C10241D895EE (8), 0XBB1205C00241D885EE (9), 0XBB20C18500D60241D842EE (11)

time remaining (calculated by converting hours to min):

also starts right after BB but D6 follows the time remaining value 63H32M (3812MIN) - 0XBB3812D675EE (6) 70H:48M (4248MIN) - 0XBB4248D6014464D723EE 97H:13M (5833MIN) - 0XBB5833D640EE

amp hours remaining:

value is between D5 and D2 28.325AH - 0XBB243658D5028325D2141314F360EE (15) 28.324AH - 0XBB243667D5028324D2141323F389EE (15) 28.296AH - 0XBB243908D5028296D2141724F315EE (15) 25.819AH - 0XBB265954D5025819D2202450F327EE (15) 25.818AH - 0XBB265963D5025818D2202459F350EE (15) 25.817AH - 0XBB265972D5025817D2202508F384EE (15)

amp (load):

3.5A - BB0350C14487D882EE (9), BB0350C14490D891EE (9) couldnt find many results, can be calculated from watts / volts, so its not crucial.

SoC:

couldn't find any results, but this can be calculated by amp hours remaining / the total battery aHs (not sure if that value is obtainable via BT or will have to be set in config).

.

If anyone can help, it would be greatly appreciated! The battery monitor is great so far and about 1/3 of the price of other BT enabled shunts, so I'm really hoping to get something working.

Olen commented 1 year ago

Hi, and thanks for the effort. I think you might be on to something, and maybe it makes more sense if you reverse the bytestream to get the parameters, and then reverse the bytes in the values again

That seems to give you the following:

EE - Start of Stream C0 - Voltage C1 - Amp D2 - Amp hours remaining D5 - ? D6 - Time remaining D8 - Watts F3 - ? BB - End of Stream

Some of your examples:

0XBB1204C00240D883EE EE - SoS 83 - ?? (checksum?) D8 - 0240 Watts C0 - 1204 Volts BB - EoS

0XBB1204C00481D850EE EE - SoS 50 - ?? (checksum?) D8 - 0481 Watts C0 - 1204 Volts BB - EoS

0XBB1230C020C10246D858EE EE - SoS 58 - ?? (checksum?) D8 - 0246 Watts C1 - 20 Amps C0 - 1230 Volts BB - EoS

0XBB243658D5028325D2141314F360EE EE - SoS 60 - ?? (checksum?) F3 - 141314 Unknown D2 - 028325 Amp hours remaining D5 - 243658 Unknown BB - EoS

In some of the strings, C1 is just one byte and in others it is two:

0XBB1232C050C10616D864EE EE - SoS 64 - ?? (checksum?) D8 - 0616 Watt C1 - 50 (one byte) Amp? C0 - 1232 Volt BB - EoS

BB0350C14487D882EE EE - SoS 82 - ?? (checksum?) D8 - 4487 Watt C1 - 0350 (two bytes) Amp? BB - EoS

Not sure how to interpret those, or how to split the strings if the field has a variable length. Since it seems like the parameter "names" are hex while all the values are decimal, you could just read the string byte by byte in reverse order and each time you find one of the known parameter identifiers, you read up to the next known identifier. Then you need to choose whether you believe the value is sane or not. E.g is a one byte Amp a sane value, or should you throw those values away until you understand them? 0.5 Amp do make sense in the real world, but do you ever see a C1 with 0000 (or 0050), or is it always just one byte if it is < 100?

chriskomus commented 1 year ago

Awesome, that helps a lot! I'm going to take a look and see what I can come up. Reversing the order and reading values between parameter identifiers seems like the best option given that values have variable lengths.

You're right in that amps are always one byte if under < 100. I don't see C1 with something like 0050 at all for example. Same goes for all other values.

I looked at all other possible params and couln't find much, so I suspect SoC isn't being transmitted and is instead being calculated.

D3 unknown: increments sporadically (a few per test): BB243955D56975D311EE BB243962D5028290D26976D3141818F322EE BB267205D5010126D3204541F317EE BB267213D5010127D3204549F340EE

D5 and F3 unknown: they increment continally with many per test, often one after the other: at idle: BB265894D5202350F364EE BB265895D5202351F366EE BB265896D5202352F368EE BB265897D5202353F370EE

when charging includes D2 (ah remaining) and D4 (unknown) also incremements: BB275488D5025681D20258D4230344F337EE BB275489D5025682D20259D4230345F341EE BB275490D5025683D20261D4230346F358EE BB275491D5025684D20262D4230347F362EE

The device records date/time, so maybe one of those is a timestamp?

D7: always 3 bytes, can't figure out what its for BB0331D6012000D701EE BB012285D770EE BB0340C1012058D74362D864EE

BB4498D6026964D743EE BB3748D6029464D793EE BB1207C09163D6022320D746EE

I need to test using heavier loads instead of this old test battery with <1 amp loads to see how larger values (for amps and watts) are transmitted.

chriskomus commented 1 year ago

Got it working! Will do some more testing and make a PR when it's ready.

I added a MonitoringDevice class, which inhereits from BatteryDevice, because I wanted to add minutes remaining, and also when drawing power it displays a negative value (ie: -50watts) to differentiate when supplying power.

image

sm-green commented 5 months ago

@chriskomus Have you gotten this to the point of creating a PR? I'm interested in this plugin as well. Thanks!

Olen commented 5 months ago

I added a MonitoringDevice class, which inhereits from BatteryDevice, because I wanted to add minutes remaining, and also when drawing power it displays a negative value (ie: -50watts) to differentiate when supplying power.

Isn't power just a function of voltage * current, so a negative current equals a negative power?

And I wonder how mins_remaining is calculated. After monitoring my batteries for a few years, I am still loking for the perfect formula to calculate that based on the soc, capacity and current. Both when charging and when using the batteries, the current fluctuates so much that trying to calculate remaining charge time or usage time gets really hard. Atm. I use the average of the last 10 current-measurements and use that as a basis, and it gives me numbers that are at least somewhat useful under load.

chriskomus commented 5 months ago

@sm-green it's been awhile since I've looked at this project but I will be revisiting the plugin soon when I get my camper trailer out of storage. I ended up mostly finishing the plugin, but then ended up using a different solution with grafana/prometheus last summer. I would like to finish this up and create a PR though, as there is quite a bit of development that I've done since last year.

@Olen , for minutes remaining I just used the value that the Junctek device returns. It's really inaccurate though, and fluctuates wildly based on load. Your solution of using the last 10 current-measurements sounds way better! I'll take a look. I will also add a number of new fields/values that have been discovered from the bytestream and make a PR soon when its ready.

Olen commented 5 months ago

Yeah. The "Minutes remaining" I have made is made in Home Assistant, not in this code, though.

I think a better approach would be to use for instance the average of the last 10 minutes, not the last 10 datapoints, because sometines I get 10 datapoints in 10 seconds, and sometimes it only report once every 15 minute when I force the data-refresh, so when the sun disappears, or if load is suddenly stopped because the power is turned off it can take hours before the average of 10 measurements reach 0.

sclawer commented 3 months ago

I am also interested in the plugin for Junktek..