Skip to content
View in the app

A better way to browse. Learn more.

Power Forum - Renewable Energy Discussion

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Muttley

Members
  • Joined

  • Last visited

Reputation Activity

  1. Like
    I've made a small tweak to my markdown card with regard to the information it displays.
    I've added in a check to indicated if the SOH of the battery drops below 100% to display a warning, see below:

    This is the updated markdown section if anyone want to incorporate that as well.
    IndBattMarkdownv2.yaml
  2. Like
    Sure thing.
    I'm using a Grid-layout Dashboard:

    My layout config is as follow, adjust to fit your needs:
    grid-template-columns: 35% 35% 10% 10% 10% grid-template-rows: auto grid-template-areas: | "flow flow flow2 flow2 flow2" "batt1 batt2 acc acc acc" justify-items: stretch mediaquery: "(max-width: 800px)": grid-template-columns: 100% grid-template-areas: | "flow" "batt1" "batt2" "flow2" "acc"Here is one of the pairs of yaml.
    IndBatts.yaml
    Just adjust your parameters to your battery specs.
    There is also 2 monitors related to the Temp section. One for min and max with 🌡️ icon and one for when there is a big deviation on the temp sensors ⚠️icon. Adjust or remove as you see fit.
    Note I've set them up in a pair configuration so that when viewed on my phone I have pair showing in one row, you can split it off as 4 indivuals if you want but this is how I have mine setup.


  3. Like
    Please share your YAML... I need this on my dashboard 😁
  4. Like
    @slipx I've seen this request on your github and here for more batteries in the card (3, 4 and 5 etc).
    Seeing as this card is severely space limited with all the info and options already added in, the only option I see for more batteries in the card self beyond the 2 battery option currently, is when running it in full mode and on a wide panel setup. Just trying to think about how you would incorporate that to the card makes my brain hurt. So what I've done is add my batteries using standard grid layout cards and markdown cards below this one to get what I want on my one dashboard.
    It is still WIP but perhaps the easiest solution to all those request for additional batteries would be to make an independent card for just batteries or enable an option that the card can be setup for just displaying the battery section that can then be stacked up or something 🤷‍♂️.
    This option using markdown cards however is very flexible and customizable to setup your own info and monitoring.

  5. Thanks
    @Muttley what BMs system does your battery use?
    My batteries uses the Pace BMS system so I'm using this integration to pull it to HA:
    https://github.com/Tertiush/bmspace
    If it uses something else you might need to look if it isn't perhaps on this list of other integrations:
    https://powerforum.co.za/topic/27424-reading-battery-data-into-esphome/
    My connectioin setup is using a EPS32 but that is just as a WiFi link from the RS232 to the server as the server is to far from the Batteries so the integration I use have the option of direct serial(usb) or IP address. 

    With the Pace BMS you just hook it to the master battery setup the integration and it pulls all the battery entities into MQTT for all the batteries connected to the master.
    My wiring setup you can see over here:
    https://powerforum.co.za/topic/16639-revov-r100-rj232-pin-diagram/#findComment-213257
    As for the card config this is the config for one of the batteries, you will just need to adjust accoding to your sensor naming.
    type: vertical-stack cards: - type: custom:stack-in-card keep: margin: false box_shadow: false background: false cards: - type: grid square: false columns: 1 cards: - type: markdown content: >- <center><font size=4><b>Battery 1:&nbsp; {% if states('sensor.generic_lithium_pack_1_current') | float < 0 %} <font color="orange">Discharging</font> {% elif states('sensor.generic_lithium_pack_1_current') | float > 0 %} <font color="#3090C7">Charging</font> {% else %} <font color="#18f50c">Floating</font> {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: vertical-stack cards: - type: horizontal-stack cards: - type: vertical-stack cards: - type: vertical-stack cards: - type: entity card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } entity: sensor.generic_lithium_pack_1_voltage name: Total voltage icon: none - type: entities card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } entities: - entity: sensor.generic_lithium_pack_1_full_capacity name: Capacity card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_remaining_capacity name: Remaining card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_cell_max_volt_diff name: Max Volt Diff card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_balancing1 name: Balancing card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - type: vertical-stack cards: - type: vertical-stack cards: - type: entity entity: sensor.generic_lithium_pack_1_current name: Total Current icon: none card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: entities card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } entities: - entity: sensor.generic_lithium_pack_1_state_of_health name: SOH card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_state_of_charge name: SOC card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_cycles name: Cycles card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - entity: sensor.generic_lithium_pack_1_balancing2 name: Balancing card_mod: style: hui-generic-entity-row: $: | state-badge { display: none; } .info { margin-left:0 !important; Color: white; } - square: false type: grid cards: - square: false type: grid cards: - type: markdown content: |2- <center><font color="#18f50c"><font size=3>Cell 01-04&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_1') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_1') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_1') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_1') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_1') }} °C {% endif %} <br> Cell 05-08&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_2') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_2') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_2') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_2') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_2') }} °C {% endif %} <br> NOS Temp&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_5') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_5') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_5') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_5') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_5') }} °C {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: markdown content: |2- <center><font color="#18f50c"><font size=3>Cell 09-12&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_3') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_3') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_3') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_3') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_3') }} °C {% endif %} <br> Cell 13-16&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_4') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_4') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_4') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_2') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_4') }} °C {% endif %} <br> ENV Temp&nbsp; {% if states('sensor.generic_lithium_pack_1_temperature_6') > states('input_number.bms_max_batt_temp') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_temperature_6') }} °C</font> {% elif states('sensor.generic_lithium_pack_1_temperature_6') < states('input_number.bms_min_batt_temp') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_temperature_6') }} °C</font> {% else %} {{ states('sensor.generic_lithium_pack_1_temperature_6') }} °C {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } columns: 2 - square: false type: grid cards: - type: markdown content: |2- <center><font color="#18f50c"><font size=3>01.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_1_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_1_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_1_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_1_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_1_voltage') }} mV {% endif %} <br> 02.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_2_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_2_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_2_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_2_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_2_voltage') }} mV {% endif %} <br> 03.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_3_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_3_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_3_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_3_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_3_voltage') }} mV {% endif %} <br> 04.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_4_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_4_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_4_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_4_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_4_voltage') }} mV {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: markdown content: |2- <center><font color="#18f50c"><font size=3>09.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_9_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_9_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_9_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_9_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_9_voltage') }} mV {% endif %} <br> 10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_10_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_10_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_10_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_10_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_10_voltage') }} mV {% endif %} <br> 11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_11_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_11_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_11_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_11_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_11_voltage') }} mV {% endif %} <br> 12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_12_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_12_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_12_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_12_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_12_voltage') }} mV {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: markdown content: |2- <center><font color="#18f50c"><font size=3>05.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_5_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_5_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_5_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_5_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_5_voltage') }} mV {% endif %} <br> 06.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_6_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_6_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_6_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_6_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_6_voltage') }} mV {% endif %} <br> 07.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_7_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_7_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_7_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_7_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_7_voltage') }} mV {% endif %} <br> 08.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_8_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_8_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_8_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_8_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_8_voltage') }} mV {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } - type: markdown content: |2- <center><font color="#18f50c"><font size=3>13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_13_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_13_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_13_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_13_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_13_voltage') }} mV {% endif %} <br> 14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_14_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_14_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_14_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_14_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_14_voltage') }} mV {% endif %} <br> 15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_15_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_15_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_15_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_15_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_15_voltage') }} mV {% endif %} <br> 16.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {% if states('sensor.generic_lithium_pack_1_cell_16_voltage') > states('input_number.bms_max_voltage_cell') %} <font color="#3090C7">{{ states('sensor.generic_lithium_pack_1_cell_16_voltage') }} mV</font> {% elif states('sensor.generic_lithium_pack_1_cell_16_voltage') < states('input_number.bms_min_voltage_cell') %} <font color="orange">{{ states('sensor.generic_lithium_pack_1_cell_16_voltage') }} mV</font> {% else %} {{ states('sensor.generic_lithium_pack_1_cell_16_voltage') }} mV {% endif %} <br> card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } columns: 2 columns: 1 - type: custom:stack-in-card keep: margin: false box_shadow: false background: false cards: - type: grid square: false columns: 1 cards: - type: markdown content: >- <center><font size=4><b>Warning:<br> <font color="orange">{{states('sensor.generic_lithium_pack_1_warnings')}} card_mod: style: | ha-card { box-shadow: none; background: rgba(0,0,0,0); border: white solid 1px !important; } grid_options: columns: full view_layout: column: 1 Just want to credit Dimumal for this card as I found this over on the HA community and tweaked it to my liking:
    https://community.home-assistant.io/t/jk-bms-integration/604035/8
  6. Like
    Hi @Muttley @IggyP . Its a known issue with that card. Here is a link to the fix
    https://github.com/AmoebeLabs/flex-horseshoe-card/issues/88#issuecomment-2145334978
  7. Like
    Muttley got a reaction from Youda in Measuring the water level in my Jojo Tanks in HA   
    Nicely done....😍
    When the community WhatsApp group starts moaning about there being no water, I occassionally go up and take a measurement with the tape measure - mine shows an accuracy of about 98% which works for me...
    The nerd in me also added in this to keep an eye on the raw readings (anything between 0.92 & 0.93 in my case = 100% capacity)

     
    Keep us posted on how it's working
  8. Like
    Your suspicions about the DFRobot sensor were correct. Thanks for that! I'll be doing the other 2 JoJo tanks as well that's on out farm.
  9. Like
    Hi everyone,

    I finally got time to change the INA219 sensor and things are looking very promising. I'm just waiting a bit for more data and then I'll report back.

    Thanks for the help!
  10. Like
    Muttley reacted to stormjp in Measuring the water level in my Jojo Tanks in HA   
    Okay, so I think I am winning.

    Everything is installed and working flawlessly. I have noticed that the installer of my tank system was very very conservative with the float and when the float stops the tank from filling, we are only indicating about 1980lt. So, I'll address that at some stage. The enclosure might need a little tweaking and reprinting too, but for the interim it'll do. Otherwise, I'm happy with how everything turned out. I'll monitor it for a couple of weeks and then start building one for the other tank too.
    Thanks for all the help - the inner nerd in me would not have been able to figure this out.


  11. Haha
    Nice one.You guys are way too technical for me.I just smack the side of my 5000l jojo and I can tell where the level is but of course not as accurately as you .
  12. Haha
    Muttley reacted to frivan in Measuring the water level in my Jojo Tanks in HA   
    The problem with your technique is that you have to smack yourself against the head if the level control doesn't work.
  13. Like
    Muttley reacted to stormjp in Measuring the water level in my Jojo Tanks in HA   
    Awesome, I'll have to resolder a bit and hopefully we're good to go then.

    I'll wire it all like yours and just use an additional buck converter down to 5V for the ESP32
    The trusty 3D printer is busy doing its thing for an enclosure, so once it is all done, Ill give an update.
  14. Like
    Just an update, I have received the INA219 from PiShop and will be replacing the DFRobot this weekend 😁
  15. Like
    I think it's good to have a bit of humour while we struggle with these wonderful devices. It helps taking the focus off of the frustration a bit. But yes, I definitely agree. We will get this right eventually 😂
    Thanks for the tip on the DF Robot sensor! I will buy the generic INA219 as per one of your links. I agree with your approach to diagnosing the issue.
    It will probably only arrive early next week, so I will post back when the new INA219 has been installed.
    Thanks again!
  16. Like
    Muttley got a reaction from Robbie3337 in Measuring the water level in my Jojo Tanks in HA   
    They said it'll be simple
    Ok so a few more things come to mind:
    When I had the issue yesterday, I noticed that I was not getting any values for INA219 Power (W) or and Values for INA219 Current (mA). We need these values to get the tank volume and the tank %. The way that I got this to work was a simple reboot of the 24V power supply which powers the INA219 and the probe. I then started to get W and mA data coming in.
    Your example from above is showing the exact same scenario as I had:

    I think the above is step 1 in troubleshooting but I also noticed a few other things:

    I also noticed a few more things in your esphome code which I've updated based on your original figures shared and adjusted for a single tank like yours:
     
    - platform: template name: "Tank Volume" id: tank_volume unit_of_measurement: "litres" lambda: |- constexpr float tank_radius = 1.10; // Adjust the tank radius as needed constexpr float max_height = 2.70; // Adjust the max height as needed constexpr float pi = 3.14159265f; constexpr float total_volume = pi * tank_radius * tank_radius * max_height * 1000; float percentage_full = id(current_full_percentage).state; float water_level = max_height * (percentage_full / 100.0f); float current_volume = pi * tank_radius * tank_radius * water_level * 1000; return current_volume; Your max height seems quite low compared to what it's listed on the Jojo Website - they state that the height is 3150mm and you're only accounting for a height of 2700mm. Did you put a tape measure into the tank to the bottom with water inside to check?
    I think try the above steps and lets see what it comes up with.
    You may also need to reboot the ESP32 - I think the sequence I use is: power off probe, power of ESP32, power on probe, power on ESP32.
     
  17. Like
    Muttley got a reaction from Robbie3337 in Measuring the water level in my Jojo Tanks in HA   
    No worries - glad you got sorted, I'm sure your INA219 is good!
    NB: no need to drain the tank - just pull out the probe and take it a reading. Because it's only 2 calibrations points, full and empty and thus you can just take an empty reading with the probe out the tank and one when it's full, ie: at the bottom of the tank when it's full.
    Regarding the missing values, I forgot to mention that you'll need to add in a template sensor to your configuration.yaml file:
    template: - sensor: - name: "Water Tank Level" unique_id: water_tank_level state: > {% set current = states('sensor.ina219_current') | float(default=0) %} {% set height = ((current * 5.0663) - 24.86) | round(2) %} {% if 0.000 <= height <= 72.000 %} {{ height }} {% else %} unknown {% endif %} I completely forgot the logic for the above ^ so just use claude.ai - share your esp32 code with it and this and ask it to make the necessary changes.
    Or even ask it to explain the above to you. 🙃
    Oh and also, chances are that your Jojo tank holds more than 10 000L!
     
  18. Like
    Thank you so much for your swift reply!
    Regarding the ina219 sensor - I could not find the one that you linked in stock, so I bought this one instead. According to this wiki, I matched the address with the DIP switch configuration.
    I added a "0" after the "2.7" Yesterday after your reply, and I think that was the problem. I'm still monitoring, but it looks positive, thank you!
    I'm busy draining the tank to recalibrate everything. I will keep you posted.
    Do you maybe know why my "Tank Volume" and "Current Full Percentage" aren't showing any data?
     
    Again, thank you so much!
     
     


  19. Like
    Muttley got a reaction from Youda in Measuring the water level in my Jojo Tanks in HA   
    So 3 things that I noticed when compared to my code:
    - your ina219 address is  0x45 - mine is 0x40
    - I also noticed that your calibration numbers seem very low - perhaps adjust the point above and below and try take new calibrations.
    - the float max_height is only 1 decimal place - perhaps make this 3
    Here's my code in case :
    captive_portal: i2c: sda: 21 scl: 22 sensor: - platform: ina219 address: 0x40 shunt_resistance: 0.1 ohm current: name: "INA219 Current" id: ina_current accuracy_decimals: 5 filters: - multiply: 1000 #convert from Amps to mA unit_of_measurement: "mA" power: name: "INA219 Power" accuracy_decimals: 5 bus_voltage: name: "INA219 Bus Voltage" accuracy_decimals: 2 shunt_voltage: name: "INA219 Shunt Voltage" id: ina219_shunt_voltage accuracy_decimals: 5 max_voltage: 32.0V max_current: 400mA update_interval: 10s - platform: template name: "Water Level" id: water_level unit_of_measurement: 'm' accuracy_decimals: 3 update_interval: 60s lambda: |- float shunt_voltage = id(ina219_shunt_voltage).state; float full_voltage = 0.00092; // Voltage at full condition float empty_voltage = 0.00042; // Voltage at empty condition float max_height = 1.570; // Adjust the max height as needed // Calculate water level based on calibration float slope = (max_height - 0.0) / (full_voltage - empty_voltage); float intercept = max_height - slope * full_voltage; float water_level = slope * shunt_voltage + intercept; // Ensure water level is within bounds water_level = std::max(0.0f, std::min(water_level, max_height)); ESP_LOGD("custom", "Shunt Voltage: %.5f V", shunt_voltage); ESP_LOGD("custom", "Water Level: %.5f m", water_level); return water_level; - platform: template name: "Current Full Percentage" id: current_full_percentage unit_of_measurement: '%' accuracy_decimals: 1 update_interval: 60s lambda: |- float max_full_reading = 9.2; // Adjust the maximum reading at full water level float min_empty_reading = 4.2; // Adjust the minimum reading at empty water level float current_reading = id(ina_current).state; float current_full_percentage = 100.0f * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading); return std::max(0.0f, std::min(current_full_percentage, 100.0f)); - platform: template name: "Tank Volume" id: tank_volume unit_of_measurement: "litres" lambda: |- constexpr float tank_radius = 0.71; // Adjust the tank radius as needed constexpr float max_height = 1.57; // Adjust the max height as needed constexpr float pi = 3.14159265f; constexpr float total_volume_single_tank = pi * tank_radius * tank_radius * max_height * 1000; float percentage_full = id(current_full_percentage).state; float water_level = max_height * (percentage_full / 100.0f); float current_volume_single_tank = pi * tank_radius * tank_radius * water_level * 1000; float total_volume_both_tanks = 2 * current_volume_single_tank; return total_volume_both_tanks; - platform: template name: "Days of Water Left" id: days_of_water_left unit_of_measurement: "days" accuracy_decimals: 1 update_interval: 60s lambda: |- float total_volume = id(tank_volume).state; float daily_usage = 1100.0; // 1100 liters per day float days_left = total_volume / daily_usage; // Cap the maximum days to 5 when tanks are full if (days_left > 5.0) { return 5.0; } return std::max(0.0f, days_left); - platform: template name: "Daily Water Consumption Rate" id: daily_water_consumption unit_of_measurement: "L/day" accuracy_decimals: 1 update_interval: 3600s # Update hourly lambda: |- static float last_volume = id(tank_volume).state; static unsigned long last_update = 0; float current_volume = id(tank_volume).state; unsigned long current_time = millis(); float consumption_rate = 0; if (last_update > 0) { float volume_change = last_volume - current_volume; float days_elapsed = (current_time - last_update) / (1000.0 * 60 * 60 * 24); consumption_rate = volume_change / days_elapsed; } last_volume = current_volume; last_update = current_time; return std::max(0.0f, consumption_rate); - platform: template name: "Tank Refill Rate" id: tank_refill_rate unit_of_measurement: "L/hour" accuracy_decimals: 1 update_interval: 300s # Update every 5 minutes lambda: |- static float last_volume = id(tank_volume).state; static unsigned long last_update = 0; float current_volume = id(tank_volume).state; unsigned long current_time = millis(); float refill_rate = 0; if (last_update > 0 && current_volume > last_volume) { float volume_change = current_volume - last_volume; float hours_elapsed = (current_time - last_update) / (1000.0 * 60 * 60); refill_rate = volume_change / hours_elapsed; } last_volume = current_volume; last_update = current_time; return refill_rate; - platform: template name: "Time to Empty" id: time_to_empty unit_of_measurement: "hours" accuracy_decimals: 1 update_interval: 60s lambda: |- float current_volume = id(tank_volume).state; float consumption_rate = id(daily_water_consumption).state / 24.0; // L/hour if (consumption_rate > 0) { return current_volume / consumption_rate; } else { return 0; // Avoid division by zero } - platform: template name: "Time to Full" id: time_to_full unit_of_measurement: "hours" accuracy_decimals: 1 update_interval: 60s lambda: |- float current_volume = id(tank_volume).state; float max_volume = 4973.0; // Maximum volume of both tanks float refill_rate = id(tank_refill_rate).state; if (refill_rate > 0) { return (max_volume - current_volume) / refill_rate; } else { return 0; // Not currently filling } - platform: template name: "Water Usage Efficiency" id: water_usage_efficiency unit_of_measurement: "%" accuracy_decimals: 1 update_interval: 3600s # Update hourly lambda: |- float actual_consumption = id(daily_water_consumption).state; float expected_consumption = 1100.0; // Expected daily usage if (expected_consumption > 0) { float efficiency = (expected_consumption - actual_consumption) / expected_consumption * 100; return std::min(100.0f, std::max(0.0f, efficiency)); } else { return 0; } - platform: template name: "Water Self-Sufficiency Duration" id: water_self_sufficiency unit_of_measurement: "days" accuracy_decimals: 1 lambda: |- float total_volume = id(tank_volume).state; float actual_consumption = id(daily_water_consumption).state; if (actual_consumption > 0) { return total_volume / actual_consumption; } else { return id(days_of_water_left).state; // Fallback to the standard calculation }  
  20. Like
    Muttley got a reaction from zsde in Measuring the water level in my Jojo Tanks in HA   
    Hi all,
    Thought I'd share my journey in creating an accurate water level measuring system for my Jojo tanks.
    I've finally managed to find a solution which is about 99.6% accurate. This equates to a water height difference of +-5mm between the actual height in the tank vs what the probe is reading. I'd call this a success 🙃
    Some of the other ESP32 + sensor solutions which I've tried and given up on:
    Waterproof ultrasonic sensor - difficult to implement as the minimum distance between the sensor and the water level is +-20CM if I recall correctly. This meant that I would need to 3D print a cone to raise the ultrasonic sensor and cut a large hole in the Jojo Tank. Plus the issues of condensation on the sensor. Analog water pressure sensor - this was attached to the bottom of the outlet of the tank. The readings were all over the place and I'd see random drops for no apparent reason so I gave up on this. Throw in pressure sensor + ADS1115 A/D Module + voltage regulation - this was probably the longest standing solution that I had in place. The results were very erratic and I'd see random fluctuations for no apparent reason. Landed up having to re-calibrate multiple times - definitely something was wrong. After advice from others on the Home Assistant Forum, I tried a solution which was suggested by others and it's been spot on and much easier to implment!
    Hardware:
    ESP32 24V Power Supply DC - DC Voltage Regulator DF Robot Throw in submersible pressure sensor INA219 Current Sensor USB Power Supply Misc conduit and enclosure
    2 Measurements were taken to calibrate:
    1: when the sensor was not inside the tank 2: when the sensor was in the tank and the tank was full (manual float switch had stopped filling). As seen in the code below:
          float full_voltage = 0.00092; // Voltage at full condition
          float empty_voltage = 0.00042; // Voltage at empty condition
    &
          float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
          float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level
    As there are 2 tanks and only 1 sensor, the total volume is multiplied by 2.
    Both tank levels equalize when they're full and are thus same.
    YAML:
    captive_portal: i2c: sda: 21 scl: 22 sensor: - platform: ina219 address: 0x40 shunt_resistance: 0.1 ohm current: name: "INA219 Current" id: ina_current accuracy_decimals: 5 filters: - multiply: 1000 #convert from Amps to mA unit_of_measurement: "mA" power: name: "INA219 Power" accuracy_decimals: 5 bus_voltage: name: "INA219 Bus Voltage" accuracy_decimals: 2 shunt_voltage: name: "INA219 Shunt Voltage" id: ina219_shunt_voltage accuracy_decimals: 5 max_voltage: 32.0V max_current: 400mA update_interval: 10s - platform: template name: "Water Level" id: water_level unit_of_measurement: 'm' accuracy_decimals: 3 update_interval: 60s lambda: |- float shunt_voltage = id(ina219_shunt_voltage).state; float full_voltage = 0.00092; // Voltage at full condition float empty_voltage = 0.00042; // Voltage at empty condition float max_height = 1.570; // Adjust the max height as needed // Calculate water level based on calibration float slope = (max_height - 0.0) / (full_voltage - empty_voltage); float intercept = max_height - slope * full_voltage; float water_level = slope * shunt_voltage + intercept; // Ensure water level is within bounds water_level = water_level < 0.0 ? 0.0 : water_level; water_level = water_level > max_height ? max_height : water_level; ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state); ESP_LOGD("custom", "Water Level: %.5f m", water_level); return water_level; - platform: template name: "Current Full Percentage" id: current_full_percentage unit_of_measurement: '%' accuracy_decimals: 1 update_interval: 60s lambda: |- float max_full_reading = 9.2; // Adjust the maximum reading at full water level float min_empty_reading = 4.2; // Adjust the minimum reading at empty water level float current_reading = id(ina_current).state; if (current_reading <= min_empty_reading) { return 0.0; } else if (current_reading >= max_full_reading) { return 100.0; } else { float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading); return current_full_percentage; } - platform: template name: "Tank Volume" id: tank_volume unit_of_measurement: "litres" lambda: |- float tank_radius = 0.71; // Adjust the tank radius as needed float max_height = 1.57; // Adjust the max height as needed float total_volume_single_tank = 3.14159265 * tank_radius * tank_radius * max_height * 1000; float percentage_full = id(current_full_percentage).state; float water_level = max_height * (percentage_full / 100.0); float current_volume_single_tank = 3.14159265 * tank_radius * tank_radius * water_level * 1000; float total_volume_both_tanks = 2 * current_volume_single_tank; return total_volume_both_tanks; We had a water outage today so I had an opportunity to test the sensor value (height) vs the actual height with a tape measure and I was off by 5mm, so I'll take this as a success.


    Hope this is useful to you guys - shout if I can answer any questions
  21. Thanks
    Muttley reacted to slipx in Home Assistant Sunsynk Power Flow Card and Dashboard   
    Hi. Those should be added to the load section
    load: show_aux: false off_colour: grey show_daily: true animation_speed: 8 max_power: 8000 load1_name: Geyser load1_switch: switch.geyser load1_icon: sensor.template_mdi auto_scale: true path_threshold: 90 etc
  22. Like
    Muttley reacted to -cK- in Revov R100 RJ232 Pin Diagram   
    @DaveMM I've got my connectors and missing parts today so here is the setup as those diagrams might not be to clear on the viewing perspective for the numbering:
    RJ12
    Pin 3 (Blue) TX
    Pin 4 (Blue/White) RX
    Pin 5 (Brown) GND

    DB9
    Pin 2 (Blue/White) RX
    Pin 3 (Blue) TX
    Pin 5 (Brown) GND



    If you are hooking this to an ESP32 then
    From the MAX3232 Converter to ESP32
    GND - GND
    TX - TX2
    RX - RX2
    VCC - 3v3
    Hope this helps.
  23. Like
    Muttley reacted to -cK- in Home Assistant Sunsynk Power Flow Card and Dashboard   
    Excellent Thanks @Sidewinder
    Might just be worth the effort then just need to figure out how to get a RS232 connected between the battery pack and Server over a 30meter cat 5e.  I'm using that for the RS485 to the inverter and can pair off a twisted pair to a RS232 but I don't think the RS232 can carry signal that far (well according to chatGPT that is) so might need to go with a EPS32 bridge setup/RS232 to RS485 adapters on both ends or something.  Time to go some more research and digging down this rabbit hole 😄
  24. Haha
    I can dream, can't I?🤪
    Basically, the big green block represents the pack info, as generated by the inverter (holistic view), with a Nav. path the graphs. The SOC%, time to full etc, stays below that. Data for each battery displayed inside the battery. 
     
    Then instead of the 44% info to the right, display each bank's cell delta voltage difference. (I ran out of drawing skills) - not a biggy, as each batteries' navigation path can take one to a more detail summary/graph/info page.
     
    BTW, I have a USB/RS232 cable direct from the master battery to my HA server to collect all the batteries entities, so I have them all available. Fortunately, my batteries have Pace BMS, which does make life a little bit easier to get the info into HA.
  25. Thanks
    Muttley reacted to slipx in Home Assistant Sunsynk Power Flow Card and Dashboard   
    v6.0.0
    What's Changed
    🚀 Exciting New Features
    This release adds a long awaited wide screen view across the lite, compact and full cards. This lays the ground work to display two batteries and possible master and slave inverter pairs. It also looks better on tablets when displaying the card in panel/full screen.
    - feat: new wide screen view to display content in 16:9 format. set `wide:true`
    - feat: display up to 6 additional essential loads when using the wide screen view
    - feat: display up to 3 non essential loads when using the wide screen view
    - fix: grouping of SVG elements and standardise viewbox across lite,compact and full cards
    - locale: update Ukraine translation

     

    Other Changes
    * New wide screen view by @slipx06 in https://github.com/slipx06/sunsynk-power-flow-card/pull/556

    **Full Changelog**: https://github.com/slipx06/sunsynk-power-flow-card/compare/v5.4.0...v6.0.0

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.