-
Notifications
You must be signed in to change notification settings - Fork 12
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
start/stop mqtt button/switch #39
Comments
Someone will need to sort out how to parse the commands. Notably the checksum at the end. home-assistant/core#86588 (comment) |
@MrDrew514 if you want to capture some logs for us turn on " |
Here is a part of the logs when I spam the resume command using the EnelX app (iOS)
Will post a 30 interval in a min Here:
It looks like it's sending 2 commands so I'm guessing my car is fully charged so it sends a resume then a stop charging command? |
The command parameter seems to alternate constantly between C244, C242, C008 and C006 which don't really make sense to me. 2023-11-24 17:05:24,229 DEBUG remote: b'CMD51705A0040M040C244S509!5UF$' (Normal script operation command) When I click the resume button those 2 are sent; 2023-11-24 17:05:27,208 DEBUG remote: b'CMD51705A0040M040C006S510!J90$' then another time 2023-11-24 17:06:50,309 DEBUG remote: b'CMD51706A0040M040C006S514!BJ9$' (Normal script operation command) When I click the resume button those 2 are sent; 2023-11-24 17:06:52,831 DEBUG remote: b'CMD51706A0040M040C242S515!ZWC$' |
@MrDrew514 your Juicebox is a 40A version ? Maybe the M is related to the MAX current, mine sends to server M and C with 24 which was the values that are my last limit used on the home assistant integration when it was wokring few days ago. I cannot test now the commands as mine is offline on enel app
|
Yeah pretty sure the Mxx is the amperage. These are the commands it receives when changing the amperage in the Enel X Way app:
My Juicebox is a 32A version (3-phase) from 2018 running the ZAP firmware. |
So far I have this: CMD
6 # day of week? (6 = Saturday)
2210 # local time (22:10)
A20 # model type? (MrDrew541's shows A0040)
M18 # Amperage (18A)
C006 # Command? Alternates between C242, C244, C008, C006
S006 # unique message ID (increments by one for every message until 999 then it loops back to 001).
!31Y$ # checksum? I think the command is the most interesting. I’ve only tried this with my car plugged in at 100%, so perhaps that’s why the commands alternate like that (it tries to start, then it pauses again, etc.). As soon as I get the chance I’ll try replaying some of these messages to see if they actually do something when my car needs charging. |
Hello, I am the original author of the juicenet integration in HA. I no longer have my juice box charger, but I used nodered for many years to "intercept" and forward the udp packets like juicepassproxy does and also saved them all into MySQL. I'll need to look if I have the database around still, but I never figured out the checksum. As above, basically the server just sends the max amps that the charger is allowed to charge the car with at the current point in time. I wrote a question on stack overflow 3.5 years ago but didn't get any useful answers to help crack it. Jesse |
Oh boy! I can definitely help here. Our biggest hurdle is going to be the checksum at the end of the command. I had been hoping that, some day, some community would sprout up and we could build a local server for these things. Enel has done horrible things to the app capabilities of these boxes, making them impossible to recommend - and it drags on me a lot. "M40" is actually offline amperage - it's stored in the microcontroller's EEPROM as "wire rating" (in old JuiceNet web portal parlance), and it takes effect immediately on startup. Every report packet it sends (081708...blahblah) should be accompanied by a reply "CMD" string, regardless if nothing has changed. Precedence of amperage limit is: Unit rating > Offline ampcmd > Runtime ampcmd. So if unit rating is 32, sending offline amperage 40 / runtime 40, the unit rating (baked into firmware code, non-modifiable) takes precedence and you get 32 amps. If unit rating=40, offline=32, runtime=16, you get 16 amps. Similarly, unit=40, offline=16, runtime=32, you ought to get 16 amps, but server architecture always prevented that from being sent, so the behavior may be undefined (if it's online, it should go 32, but if it goes offline / hasn't received a command in about 5 minutes, you may get 16). The rest is setting the internal clock based on the local time zone for offline time of use - if I'm recalling/reading correctly, the first part of the command (several numeric digits) is setting the clock, and the final one is sending time-of-use hours with a bit mask (weekday start, weekday end, weekend start, weekend end) - this is all inherited from wayyyy old protocol back in 2014 or so when this silly protocol was first devised. There is also a bit mask in there that determines "whether the user is looking at the app now", which increases the report interval from 10 seconds when charging (I believe) and 30 seconds when idle, to 3 seconds for both modes. The "!XYZ$" at the end is a checksum of the command, using some formula held in the bowls of the ancients. If the checksum doesn't match, it won't accept the command (should give some "DBG" string in return as a fault message). The runtime reporting is much more complex and there are two packet types: active charging (J1772 state C), or idle/not charging (any other state). It has voltage, current, frequency, echoed ampcmd (repeating back what it's told to run at). and a 96-slot interval memory (saying how many watt-hours were used in each of 96 15-minute periods of the past 24 hours of run time, calibrated to the clock setting it was given with CMDs). In the early years of JuiceBox, fine-tuning the implementation of the interval counter was one of the first things I contributed to :) If we can crack how to get traffic reliably proxied to the HA server instead of the cloud, I guarantee we can fully implement this in short time! |
Let's work on cracking that checksum. As I recall, the checksum is performed on the full string (from 081708...) up to (not including) the ! of the checksum for outgoing messages, but appears to include the "!" for CMD messages. The actual hashing is done using some code found in the bowels of some early Arduino-based JB firmware, before the code went fully closed-sourced, thankfully:
Then, you have your output uint16_t as h in the end. Finally, it uses a sort of "base35" encoding to take the 16-bit value and spread it across 3 ASCII characters. Dividing 35 at a time and working with the modulo, it maps to 0-9 then A-Y but specifically remaps "O" to "Z" to avoid confusion with the number 0. I'm still struggling to figure out the misalignment, as this doesn't result in a checksum match. Hmm... maybe it'll work with protocols prior to v7 on older units? ("v" indicated in the outgoing telemetry strings) |
@FalconFour wow, where did you find that snippet of code? Looks like it works on any data I had captured. I wish I had that 5 years ago when i started capturing..haha edit: It works with $ python main.py '0910042001260513476122621631:v09u,s627,F10,u01254993,V2414,L00004555804,S01,T08,M0040,C0040,m0040,t29,i75,e00000,f5999,r61,b000,B0000000!55M:'
Check: 55M
Decimal: 6322
CRC: 27130
Base35: 55M
$ python main.py 'CMD41325A0040M040C006S638!5N5$'
Check: 5N5
Decimal: 6935
CRC: 6935
Base35: 5N5 edit2: main.py located here: https://gist.github.com/jesserockz/276441f58892b7b425910bf9144cba39 |
@jesserockz @FalconFour I put together a little Python library for building/parsing Juicebox UDP messages: https://github.com/philipkocanda/juicebox-protocol It's got a small test suite so we can iterate on this further. Next on my list is to integrate this into Juicepassproxy and do some testing with my own Juicebox (a v7). |
I'm curious what I could do to help get further. I run HA at home and I have ... a few JuiceBoxes (want one?). I lost interest in home-lab stuff some years ago, so I just run an Xfinity-provided router that I don't think has redirect capabilities. I'm sure most potential users are similar - so maybe the best approach would be a dedicated, dirt-cheap used router-turned-proxy that can be flashed with open source firmware (e.g. Tomato, DD-WRT on some throwaway "pay you to take it" used router?), configured to pipe that traffic out to my HA server out one of its LAN ports. From there, the proxy ought to send a reply command with every message it receives to keep the box happy / "in online mode", and it'd be pretty remarkable to have local control over the box outside the buggy app (that fights me at every tap). |
@FalconFour You can also add dnsmasq addon to your HA and have all dns requests go through that, which can re-route all dns lookups to the enel servers to the juiceproxy. You can set the default dns server in the xfinity router or you can set up a guest wifi to point to the HA's dnsmasq and have the juicebox point to the guest wifi. I'm on the fence with this project as my relay just started going on the fritz, so waiting to see if this project can use juiceproxy instead of relying on enel's servers, before replacing the relay.
|
@FalconFour given we have a shell to the juicebox, can't we just change the server URL to point to our own and remove any reference to the official one? JPP partially already does this, but it leaves the official server in and adds a second one pointing to itself if I recall correctly. Do you expect we'll run into any complications that route? Like it resetting itself automatically? |
You'll be fighting a losing battle against the app on the module. No part of the JB's development was geared towards having shell or terminal access (in fact, locking it out was attempted a few times, but it kept getting forgotten). The architecture is such that there's an underlying OS (ZentriOS) that provides the terminal, and then there's an application (JNet_something or other*.zap) that runs on top of it. That application is the one printing all sorts of debug info to the serial terminal - that you only see if you open the box and connect to the UART port (8-pin, follows Arduino Pro Mini pinout with 2 reset pins added to the end, one for Atmel and one for Zentri, runs at 9600 baud). That application doesn't have any knobs or dials. It tells the OS what to do. It sets the server/port, and it itself is the one ultimately deciding what server it's going to talk to. It might make some storage use of the "udp.*" parameters within ZentriOS, but it doesn't really care about them. The app is the one opening/closing connections and making requests, via the OS, independent of those parameters (which are used for "dumb piping" for earlier JB versions). So yeah, that's been a big reason I've not had a lot of hope for local data. haha. |
I used the ZentriOS web interface on my Juicebox to change the udp server address to my nodered instance and it stayed like that for many years until I sold the charger with a car. YMMV though |
@philipkocanda have you made any progress integrating your code on juicepassproxy ? I have added support for some of extra parameters and created number sensors to allow setting values from home assistant, but now I need the code to send messages to the juicebox. |
@ivanfmartinez not yet, havent had the time but I still intend to do so. My juicebox just failed (stuck relay issue) so it might take a bit longer for me to get to it as I first have to open it up and replace the stuck relay (3-phase version so we'll see how that pans out!). I might also use this opportunity to sniff on the serial communications while the JB is in action to see if there's something interesting in there we can use, maybe dump the controller's firmware while we're at it 😈 |
technically this is "possible" but I am not sure if it will achieve the intended outcome. check here however, the reason JPP polls the device frequently is that it seems to have an internal watchdog reinstantiating these connections frequently. |
Managed to get some serial output: https://gist.github.com/philipkocanda/198d9b3fc12d5c265d173ac9723d6593 Mind you it's a 5V TTL. @FalconFour out of curiosity, does the Juicebox also accept commands over serial? |
Wow, nice! What you're seeing there is the transition from legacy protocol (where the Atmel MCU natively speaks JuiceNet protocol, talking directly to the server) to A2Z protocol (Atmel to Zentri). A2Z protocol is wildly different, meant to just tell the Zentri chip about current status, and then the Zentri handles stats and comms protocol. The earlier (fall-back) protocol is there to support Zentri chips that were using earlier firmware, that just acted as a dumb pipe between the server and Atmel chip. Thus the Atmel firmware actually also has all the logic needed to implement JN protocol. (can you believe all this stuff fit in 32KB Flash and 2KB RAM? Pfh, people use it to blink an LED these days, lol) Amusing fact: what you're seeing at the start with "$$$" isn't functionally useful - it's basically a bug left-over from legacy code, trying to get the WiFi module into command mode (which it will no longer do, when it runs a ZAP). That's the only thing that makes it hang for 30-odd seconds during startup. But it was considered a trivial enough issue to just ignore, lol. Spamming the expected reply character ">" will satisfy it quickly and move-on through the process. Pretty wild seeing a 3-phase EU JuiceBox too... those were pretty rare I think! Anyway, if you hold the WiFi (Zentri) in reset (it's one of the last two pins, simply ground it), you can indeed talk directly to it and it'll stay in legacy protocol mode. The last two pins are each of Zentri reset & Atmel reset. With Zentri in reset, try sending CMD responses and see what it says in response. A good test bed for what you might build in the protocol handler. The only header worth dealing-with is the one you're plugged into; the white header near the WiFi module is actually a secondary serial port used for future expansion (much also like the 12-pin header below). The 9-pin header to the side of the 12-pin is the SPI header for Atmel (identical to common SPI programmers you can grab on Amazon) - be careful with it; if you try to do anything with it, grab a download from the chip's fuse settings, Flash, and EEPROM space first as backup ;) If you hold Atmel in reset, you can also talk to Zentri with Tx/Rx swapped -- on startup, you should see [Ready] and a bunch of info spewing from the ZAP app when it starts. (and if you just connect your module's Rx pin and leave resets alone, you can see the whole conversation without conflicting the bus!) With Atmel in reset (as not to conflict) and Tx/Rx set to talk to Zentri, if you rapidly paste "$$$" and some commands at just the right time while toggling Zentri reset, you can intercept the ZAP app startup and send your own commands :) But you can do the same using WiFi setup mode and "10.10.10.1/command/(urlencoded-command-here)". |
@FalconFour Thank you! That is incredibly helpful and will greatly help development! |
After a lot of good information from this thread I was abve to pause the charging. If anyone else can test we can work together to make a production ready version of #69 I have used the code from @philipkocanda repository to send commands to Juicebox device |
Referenced from #77 |
I don't want to rush anyone into anything, I'm just wondering if it would eventually be possible to add a start/stop charging entity for more automation ideas.
The text was updated successfully, but these errors were encountered: