<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ESP32 on Making Clean Tech</title><link>https://nunrg.eu/tags/esp32/</link><description>Recent content in ESP32 on Making Clean Tech</description><generator>Hugo -- 0.136.5</generator><language>en-us</language><copyright>2024 Franci Kopač</copyright><lastBuildDate>Thu, 20 Mar 2025 12:58:48 +0100</lastBuildDate><atom:link href="https://nunrg.eu/tags/esp32/index.xml" rel="self" type="application/rss+xml"/><item><title>Solar System Monitor Using Three Analog Dials On E-paper</title><link>https://nunrg.eu/posts/epaper-servo-gauge/</link><pubDate>Thu, 20 Mar 2025 12:58:48 +0100</pubDate><guid>https://nunrg.eu/posts/epaper-servo-gauge/</guid><description>A solar-system monitor that shows live data on three analog-style dials drawn on an e-paper display, driven by an ESP32.</description><content:encoded><![CDATA[<p>You can support me by <a href="https://medium.com/@francikopa/solar-system-monitor-using-three-analog-dials-on-e-paper-fc45434353f0">reading this article on Medium</a> or
you can buy me a beer <a href="https://paypal.me/FranciKopac?country.x=SI&amp;locale.x=en_US">here</a>.</p>
<h2 id="introduction">Introduction</h2>
<p>Last fall I came across an interesting article in <a href="https://hackaday.com/2024/11/25/e-ink-screen-combined-with-analog-dial-is-epic-win/">Hackaday</a>, where <a href="https://arnweb.nl/gitea/arne/EinkAnalog">Arne van Itersen</a> made an interesting solar power display with an analog gauge and an e-paper screen.</p>
<p>It immediately grabbed my attention because it solves the biggest problem with e-paper displays—they need a few seconds to refresh, making them unsuitable for displaying continuously changing data like solar power. A simple analog needle takes care of that problem but is limited to displaying one thing only. But if you put the needle in front of an e-paper screen, you get continuous power information from the needle. You can then use the e-paper display for displaying things that only change every few minutes, like storage battery level, daily production, and system operation mode.</p>
<p>But using an analog dial from a multimeter seemed a bit fiddly to me, and I thought about how to improve on that. Using a small servo instead would be better, because I could use needles of any size. Controlling the servos is quite simple too, I needed the ESP32 to control the e-paper display anyway. It took a weekend to put together a simple prototype for a one gauge display, which I used for my DIY EV-charger.</p>
<figure>
    <img src="/images/epaper/1semafor.jpg" alt="EV-charger display using a needle over an e-paper display">
    <figcaption>The first try, a 1-gauge display for my EV charger</figcaption>
  </figure>
  
<p>The thing worked like a charm and got me thinking about how to improve it. I was thinking about updating my solar system display for a while now, and this seemed like a good solution.</p>
<h2 id="thinking-about-the-design">Thinking About The Design</h2>
<p>One needle wasn&rsquo;t going to cut it this time—I wanted one for solar power, one for power coming from the grid, and one for the power going into the house. After thinking about it for a while, I decided to put the grid and house power servos on the left and right side of the display. The solar servo would be on the bottom. This provides some spatial logic too—power flows from the grid (left) or solar (bottom) to the house (right). I guess putting the solar need on top could also work, but that didn&rsquo;t look right to me for some reason.</p>
<p>I wanted to put the display outside, where it would be exposed to the elements, so it needed a weatherproof housing. So I had to think a bit on how to make a housing that would be both weatherproof and easy to assemble. It&rsquo;s easy to build a two part shell, but how to design it in a way you can assemble and then disassemble it easily while keeping it watertight? I decided to approach it differently. I designed a mounting plate for the servos and the e-paper display first and gave it a flange on the sides and on the bottom. Then I designed a one-piece housing with a window and a simple top cover. This housing had simple guides to hold the flanges of the mounting plate. The window can be closed using some acrylic glued with silicone to make it weatherproof. The top cover is designed to have rainproof downslopes and only needs a drop of superglue on each side to keep it in place. This makes the assembly and testing really simple, you can do everything with the mounting plate alone.</p>
<figure>
    <img src="/images/epaper/mountplate.jpg" alt="The mounting plate with installed servos, e-paper display, and connected ESP32">
    <figcaption>The assembled mounting plate, ready for testing, only the needles are missing</figcaption>
  </figure>
  
<h2 id="the-software">The Software</h2>
<p>I&rsquo;m used to Arduino, so this is what I used. E-paper in Arduino is IMO best used with the GxEPD2 library, which includes the Adafruit GFX functions, the servos are controlled using the Servo library, data exchange is done using Adafruit MQTT, and network connectivity uses WiFi.</p>
<p>The program is subscribed to several MQTT topics, containing the values for grid power, house power, solar power, solar production, battery level, and system mode. Each of these topics is linked to a callback function that triggers on topic updates. The callback functions for grid, house and solar power all move the respective servo needles. The callbacks for battery level and solar production only update the relevant global variables. Screen refresh is only directly triggered by a system mode topic change or every 10 minutes, but this updates the display with the latest data stored in the globals.</p>
<p>Startup makes a full sweep of all the needles, serving as a kind of servo calibration check, then starts the main loop. The main loop is really short and only keeps the MQTT connection alive and resets the whole thing if Wi-Fi drops.</p>
<h3 id="getting-the-data-to-the-topics">Getting the Data To the Topics</h3>
<p>The one remaining job on the software side was to get the data from my solar system to the MQTT topics. The solar system is connected to my Home Assistant installation, so it was really easy to set up some automations that publish the relevant data to MQTT topics when the relevant sensor states change. I used state changes for triggers and the MQTT Publish service to send the data to the MQTT topic. I already had a MQTT broker set up for my other projects, so I just used that one.</p>
<h2 id="build">Build</h2>
<p>Once I was satisfied with the results, it was plain sailing:</p>
<ul>
<li>3D-print the enclosure using ABS</li>
<li>Cut the acrylic to size and glue it to the enclosure using some silicone glue</li>
<li>Drill a hole for the power cable on the appropriate spot, then use some mounting glue to fix the enclosure to the wall</li>
<li>Connect the power and insert the mounting plate in the housing.</li>
</ul>
<figure>
    <img src="/images/epaper/3semafor.jpg" alt="The finished and closed enclosure">
    <figcaption>The end product on a sunny day while charging my EV. Note to self—it&#39;s really easy to scratch acrylic with screw heads 🤦‍♂️</figcaption>
  </figure>
  
<p>You can find all the relevant code and files on <a href="https://github.com/FrenkK/servo-epaper-gauge">Github</a></p>
<p>If you found this article useful, you can buy me a beer <a href="https://paypal.me/FranciKopac?country.x=SI&amp;locale.x=en_US">here</a>.</p>
]]></content:encoded></item><item><title>How To Use Minimal Power To Control an E-paper Display With an ESP32</title><link>https://nunrg.eu/posts/lowpowerepaper/</link><pubDate>Sat, 14 Sep 2024 00:00:00 +0000</pubDate><guid>https://nunrg.eu/posts/lowpowerepaper/</guid><description>How to drive an e-paper display on minimal power with an ESP32 — deep sleep, an energy harvester and a supercapacitor instead of a battery.</description><content:encoded><![CDATA[<p>You can support me by <a href="https://medium.com/p/0f0f993d9ee0">reading this article on Medium</a></p>
<h2 id="what-do-i-mean-by-low-power">What Do I Mean by Low Power?</h2>
<p>I was involved in an art project where we wanted to use a smallish (10 x 15cm) solar panel to power an e-paper display inside a gallery, controlled by an ESP32 micro controller.</p>
<p>This would be a pretty trivial job outdoors: the panel has 5W peak power and I could just put a small DC-DC converter on it to get stable 3.3V power from it during normal daylight.</p>
<p>Indoors, the game changes completely, due to two main issues: low illuminance and low solar panel efficiency at low illuminance.</p>
<p>Outdoors, the illuminance will be anywhere from 1000 to 100000lux during the day. On the other hand, normal indoor lighting would normally range from 100 to 500lux. This alone reduces the available power from the solar cell by a factor of 200 or more. 5W turns into 25mW.</p>
<p>But there is another problem: The solar panel efficiency drops at low light. At full illuminance, the total power conversion efficiency of a modern solar panel can exceed 20%, but the same panel will have a much lower efficiency at low light due to interior current leakage. The expected 25mW turns into 5 or 10mW at most with normal indoor lighting.</p>
<p>To put this in perspective: ESP32 will consume somewhere around 900 mW transferring data via WiFi and some 20 to 70 mW with radio off. See <a href="https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/">this helpful article</a>.</p>
<p>So is there no way to power the ESP32 using our solar panel?</p>
<h2 id="the-solution">The Solution</h2>
<p>Our project involves refreshing an e-paper display at certain intervals and e-paper consumes power only during the refresh (drawing). So the solution is to somehow store the miniscule amount of available energy until there is enough to draw the next picture, turn everything on, draw the picture, save the data for the next one, and power off.</p>
<h3 id="the-hardware">The Hardware</h3>
<p>On the hardware side, I achieved this using a solar harvester chip <a href="https://e-peas.com/product/aem10941/">AEM10941</a> evaluation board that very efficiently charges a single super-capacitor. This super-capacitor in turn powers a <a href="https://www.pololu.com/product/2561">low-power, low-voltage boost converter</a> and this powers the ESP32.</p>
<figure>
    <img src="/images/epaper/powerpath.png" alt="The Power Harvesting System">
    <figcaption>The Power Harvesting System</figcaption>
  </figure>
  
<h3 id="the-software">The Software</h3>
<p>But the hardware alone is not the solution yet: I needed a way to turn off everything so the harvester has the chance to charge the capacitor up, do the drawing only when the capacitor is full and then turn off everything again until there is enough power available.</p>
<h4 id="esp32-deep-sleep">ESP32 Deep Sleep</h4>
<p>The solution is to implement the deep sleep on the ESP32. While in deep sleep, the ESP32 chip only consumes 10μA, but it powers off almost everything, leaving only a small portion of slow RTC RAM and a counter that periodically wakes it up.</p>
<p>So how does it all work?</p>
<ol>
<li>
<p>The system spends most of the time in deep sleep, where the combined power usage of the power harvesting system, converter and ESP32 never exceeds about 150μW.</p>
</li>
<li>
<p>Every 5 or 10 seconds it wakes up for a fraction of a second to measure the capacitor voltage:</p>
<p>2a. If the voltage is not high enough, it goes to deep sleep again.</p>
<p>2b. If the voltage is high enough, it draws the picture, stores the sequence number into the RTC RAM and goes to deep sleep again.</p>
</li>
<li>
<p>Rinse and repeat.</p>
</li>
</ol>
<h4 id="pick-the-right-esp32-board">Pick the Right ESP32 Board!</h4>
<p>There is a possible pitfall here: Some ESP32 development boards, like the basic ESP32 Dev Module, power additional circuitry (level converters, USB-to-RS232 chips etc.) from the 3.3V rail. This means they will always use at least 10mW of power, regardless of the deep-sleep mode, which is useless for our use case. I had really good experience with the <a href="https://www.olimex.com/Products/IoT/ESP32/ESP32-DevKit-LiPo/open-source-hardware">Olimex ESP32-DevKit-LiPo</a> boards in this respect, but there are other well built development boards out there.</p>
<h4 id="there-are-always-unintended-consequences">There Are Always Unintended Consequences</h4>
<p>Remember how the chip powers off almost everything when in deep sleep? All the regular RAM contents are lost too, only the sequence number in RTC RAM remains.
So when I try to draw the next picture, the system doesn&rsquo;t know a picture was already drawn previously and simply draws over it. The results are really ugly:</p>
<p><img loading="lazy" src="/images/epaper/ugly.gif" alt="Video of the flawed drawing"  />
</p>
<p>I spent way too much time thinking how to fix this&hellip;</p>
<p>One option would be to use a full refresh, but that would entail the annoying blinking of the whole display. Then I thought about adapting the library and storing some of it&rsquo;s variables in the RTC RAM. This seemed like a sure way to lose all my remaining hair, though.</p>
<p>After a lot of thinking, I finally thought of a nice hack. The system doesn&rsquo;t know what was displayed previously? I should draw the exact same picture as the last time to &ldquo;refresh it&rsquo;s memory&rdquo; and right afterwards draw the new one.</p>
<p>This worked beautifully:</p>
<p><img loading="lazy" src="/images/epaper/nice.gif" alt="Video of the corrected drawing"  />
</p>
<h2 id="conclusion">Conclusion</h2>
<p>Super-capacitors are a wonderful way to power small devices that work at intervals when there is not much power available. They are preferable to batteries due to their much better cycling ability. I like things that you can put on a wall and expect them to work for years and years instead of becoming electronic waste soon.</p>
<p>And if you use deep sleep with ESP32, always keep in mind the lost RAM contents when the chip wakes up again.</p>
<h2 id="the-code">The Code</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;GxEPD2_BW.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;GxEPD2_display_selection_new_style.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&#34;bitmaps/images.h&#34;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;pgmspace.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;driver/adc.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;esp_sleep.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>RTC_DATA_ATTR <span style="color:#66d9ef">int</span> pic_index <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> adcPin <span style="color:#f92672">=</span> <span style="color:#ae81ff">34</span>; <span style="color:#75715e">// GPIO34 (ADC1_CH6)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> sleepTimeSeconds <span style="color:#f92672">=</span> <span style="color:#ae81ff">3</span>; <span style="color:#75715e">// Sleep time in seconds
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> array_size <span style="color:#f92672">=</span> <span style="color:#66d9ef">sizeof</span>(images)<span style="color:#f92672">/</span><span style="color:#66d9ef">sizeof</span>(images[<span style="color:#ae81ff">0</span>]);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">int</span> refresh_size <span style="color:#f92672">=</span> <span style="color:#ae81ff">30</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setup</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Configure ADC
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#a6e22e">adc1_config_width</span>(ADC_WIDTH_BIT_12);
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">adc1_config_channel_atten</span>(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Read the voltage on pin 34
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> adcValue <span style="color:#f92672">=</span> <span style="color:#a6e22e">adc1_get_raw</span>(ADC1_CHANNEL_6);
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">float</span> voltage <span style="color:#f92672">=</span> adcValue <span style="color:#f92672">*</span> (<span style="color:#ae81ff">3.3</span> <span style="color:#f92672">/</span> <span style="color:#ae81ff">4095.0</span>); <span style="color:#75715e">// Convert ADC reading to voltage
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span> (voltage<span style="color:#f92672">&gt;</span><span style="color:#ae81ff">2.45</span>) { <span style="color:#75715e">// Only if voltage is high enough
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> (pic_index<span style="color:#f92672">%</span>refresh_size <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">||</span> pic_index<span style="color:#f92672">%</span>array_size <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) {
</span></span><span style="display:flex;"><span>      display.<span style="color:#a6e22e">init</span>(<span style="color:#ae81ff">0</span>, true, <span style="color:#ae81ff">2</span>, true); <span style="color:#75715e">// first update should be full refresh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    } <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>      display.<span style="color:#a6e22e">init</span>(<span style="color:#ae81ff">0</span>, false, <span style="color:#ae81ff">2</span>, true); <span style="color:#75715e">// following updates should be normal refresh + draw previous picture to avoid artifacts
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      display.<span style="color:#a6e22e">drawImage</span>(images[(pic_index<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)<span style="color:#f92672">%</span>array_size], <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">400</span>, <span style="color:#ae81ff">300</span>, false, false, true);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    display.<span style="color:#a6e22e">drawImage</span>(images[pic_index<span style="color:#f92672">%</span>array_size], <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">400</span>, <span style="color:#ae81ff">300</span>, false, false, true);
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>    display.<span style="color:#a6e22e">hibernate</span>(); <span style="color:#75715e">//Turn off voltage converters inside the display to save power
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>    pic_index<span style="color:#f92672">++</span>;
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// Configure the ESP32 to wake up after a fixed delay
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#a6e22e">esp_sleep_enable_timer_wakeup</span>(sleepTimeSeconds <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000000</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">esp_deep_sleep_start</span>();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> <span style="color:#a6e22e">loop</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>If you found this article useful, you can buy me a beer <a href="https://paypal.me/FranciKopac?country.x=SI&amp;locale.x=en_US">here</a>.</p>
]]></content:encoded></item><item><title>Example DIY EV Charging Point</title><link>https://nunrg.eu/posts/example_diy_charging_point/</link><pubDate>Fri, 27 Oct 2023 00:00:00 +0000</pubDate><guid>https://nunrg.eu/posts/example_diy_charging_point/</guid><description>A complete DIY EV charging point: bill of materials, schematics, ESPHome firmware and code for a simple, safe home EVSE build.</description><content:encoded><![CDATA[<p>Let’s go into details!</p>
<figure>
    <img src="/images/EV_charging/finished.jpg" alt="Finished product">
    <figcaption>What It Might Look Like</figcaption>
  </figure>
  
<p>If you’ve been reading my <a href="https://nunrg.eu/posts/diy_ev_charging/" title="DIY EV Charging">DIY EV Charging Point Basics</a> post, you probably wonder how all the options mentioned might be distilled into a practical DIY project. This post describes a charging point I actually built. I will explain why and how I made the individual choices, list an actual BOM, describe how everything is connected and even give you the configuration files I used in the first version.</p>
<h2 id="design-objectives">Design Objectives</h2>
<h3 id="some-background">Some Background</h3>
<p>I built this charging point for a neighbor friend who recently, after some deliberation, decided to start driving an EV in the best possible way for “beginners”: He bought a used short-range EV he uses as the “second car” to drive to work and do errands (he has a big family, so there are many errands to take care of). This saves him a ton of gas money and the objectively better driving experience is simply the icing on the cake.</p>
<p>Until now, he was using the charging cable he got with the car, but this was slow (only half the available charging power) and he had no handy sockets to plug it in, forcing him to use an extension cord. So we talked and I offered to help him build a proper Type 2 charging point, enabling him to use the full charging power and avoid dealing with the “cable salad”, while having everything properly prepared for the next EV that is sure to come in time. We sat down, talked and decided what to build.</p>
<h3 id="parameters">Parameters</h3>
<ul>
<li>He does not have a smart home solution, so the solution had to be standalone.</li>
<li>We decided it would be best if we installed it on the outside wall of his house, next to his driveway.</li>
<li>To keep the charging point visually clean, we would use a socket, not a cable.</li>
<li>Although his present car only has a one-phase internal charger, we decided to build a full three-phase charging point, since the difference in costs is minimal and we wanted to keep everything future-proof.</li>
<li>With 3x 20A distribution fuses, dynamic current control was a must.</li>
<li>He needs minimal access control, a switch in the house was enough.</li>
<li>There should be some easy way to charge only at night, when energy is cheaper. But there should also be an option to charge at any time to top up the car when needed.</li>
</ul>
<h2 id="design-choices">Design Choices</h2>
<p>After the parameters were set, it was relatively easy to decide on the final solution:</p>
<ul>
<li>I decided to use the <a href="https://github.com/kortas87/simple-evse">SimpleEVSE</a> controller to take care of the SAE J1772 standard signalling and control since I had good experience using it in the past.</li>
<li>I would use a ESPHome controller, connected to the WiFi to control the EVSE controller (current and time control, monitoring).</li>
<li>The charging point would have it’s own weatherproof switchboard on the outside wall, containing the fuse, relay, EVSE controller and the ESPHome controller. The socket would be built right next to it.</li>
<li>He had some space left in an auxiliary switchboard inside the house, so we would put the RCD switch there, so it can also serve as an access control switch to turn off the whole charging point when needed.</li>
<li>We would install a cheap smart electricity meter in the main switchboard to measure the currents on distribution fuses. Since this switchboard is on the other side of the house and wiring an extra data transfer cable to the charging point would be a problem, I decided to read it using a separate ESPHome controller connected to the home WiFi network.</li>
</ul>
<h2 id="the-actual-build">The Actual Build</h2>
<figure>
    <img src="/images/EV_charging/plan.png" alt="Electric diagram">
    <figcaption>The Plans</figcaption>
  </figure>
  
<p>In our case, the system is housed in two small boxes, but if your installation allows, you could connect the energy counter directly to the charge control ESPHome controller, saving yourself one extra ESPHome controller and getting better reliability.</p>
<h3 id="bom">BOM:</h3>
<h4 id="current-supervisor">Current Supervisor:</h4>
<ul>
<li>Wiring box as your situation requires</li>
<li>An energy meter with Modbus interface, e.g. <a href="https://www.ebay.de/itm/384473893449">this one</a> or <a href="https://www.ebay.de/itm/404221985277">this one</a></li>
<li>RS485 to 3.3V converter, e.g. <a href="https://www.ebay.de/itm/295361148016">this</a></li>
<li>ESP8266 or ESP32 module, e.g. <a href="https://www.ebay.de/itm/144123804853">this</a></li>
<li>A 5V power supply</li>
</ul>
<h4 id="charge-control-unit">Charge Control Unit:</h4>
<ul>
<li>Wiring box</li>
<li>RS485 to 3.3V converter, e.g. <a href="https://www.ebay.de/itm/295361148016">this</a></li>
<li>ESP8266 or ESP32 module, e.g. <a href="https://www.ebay.de/itm/144123804853">this</a></li>
<li>12V to 5V DC-DC converter, e.g. <a href="https://www.ebay.de/itm/255283194266">this</a></li>
<li>EVSE DIN controller, buy it <a href="https://shop.gwl.eu/Electric-Car-Chargers-1/EVSE-Kit-V1-1-For-EV-Charging-Station-Cable-Wallbox-Kit-Only.html">here</a>, the have many other parts for this project too</li>
<li>4-pole contactor, like <a href="https://shop.gwl.eu/Electric-Car-Chargers-1/EVSE-AC-Relay-4X40A.html">this one</a></li>
<li>A RCD, type B, like <a href="https://www.ebay.de/itm/293370848371">this one</a></li>
<li>A MCB (fuse), 16A B-type in our case</li>
<li>A 4P T2 surge protecting device (SPD), like <a href="https://www.ebay.de/itm/404534273552">this one</a></li>
<li>A type 2 socket, like <a href="https://shop.gwl.eu/Electric-Car-Chargers-1/EVSE-EV-Connector-EVSE-Mennekes-Type-2-Socket.html">this one</a></li>
</ul>
<h3 id="build-instructions">Build Instructions</h3>
<p>Use the schematic as your guide. Be careful about proper grounding, correct wire and component sizing, weatherproofing, wiring screw torques etc. DIN-rails are your friend.</p>
<p>You should have enough experience with electric projects to be able to build and customize this from the data I provided. If you don’t, it’s likely you are not able to build it safely on your own, so talk to people who understand it better.</p>
<h3 id="example-code-for-the-two-esphome-controllers">Example Code for the Two ESPHome Controllers</h3>
<h4 id="current-supervisor-1">Current Supervisor:</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">esphome</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">stevec</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">esp8266</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">board</span>: <span style="color:#ae81ff">d1_mini</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Disable logging to be able to use Modbus</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">logger</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">baud_rate</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">ota</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">wifi</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—ssid</span>: <span style="color:#e6db74">&#34;ssid&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">password</span>: <span style="color:#e6db74">&#34;pass&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">web_server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">80</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">uart</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id</span>: <span style="color:#ae81ff">mod_bus</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">tx_pin</span>: <span style="color:#ae81ff">GPIO1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">rx_pin</span>: <span style="color:#ae81ff">GPIO3</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">baud_rate</span>: <span style="color:#ae81ff">9600</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">stop_bits</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">parity</span>: <span style="color:#ae81ff">even</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">modbus</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id</span>: <span style="color:#ae81ff">modbus_stevec</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">send_wait_time</span>: <span style="color:#ae81ff">200ms</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">flow_control_pin</span>: <span style="color:#ae81ff">GPIO5</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">modbus_controller</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—id</span>: <span style="color:#ae81ff">stevec</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">24</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_id</span>: <span style="color:#ae81ff">modbus_stevec</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">update_interval</span>: <span style="color:#ae81ff">5s</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">setup_priority</span>: -<span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">sensor</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">#Template sensor</span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">template</span> <span style="color:#75715e">#Max phase current, will be written by lambda</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;TokMax&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tokmax</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">#Readouts of individual phase currents from the smart meter</span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">stevec</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tokr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;TokR&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">0x0008</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">unit_of_measurement</span>: <span style="color:#e6db74">&#34;A&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#e6db74">&#34;read&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">FP32</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—sliding_window_moving_average</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">window_size</span>: <span style="color:#ae81ff">6</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">stevec</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">toks</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;TokS&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">0x000A</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">unit_of_measurement</span>: <span style="color:#e6db74">&#34;A&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#e6db74">&#34;read&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">FP32</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—sliding_window_moving_average</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">window_size</span>: <span style="color:#ae81ff">6</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">stevec</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tokt</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;TokT&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">0x000C</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">unit_of_measurement</span>: <span style="color:#e6db74">&#34;A&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#e6db74">&#34;read&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">FP32</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—sliding_window_moving_average</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">window_size</span>: <span style="color:#ae81ff">6</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">time</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">sntp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">sntp_time</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_time</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Every 10 seconds do readout of max phase current</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—seconds</span>: <span style="color:#ae81ff">/10</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>         <span style="color:#f92672">—lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              id(tokmax).publish_state((id(tokr).state &gt; id(toks).state) ? ((id(tokr).state &gt; id(tokt).state) ? id(tokr).state : id(tokt).state) : ((id(toks).state &gt; id(tokt).state) ? id(toks).state : id(tokt).state));</span>              
</span></span></code></pre></div><p>This is simple: We talk to the Modbus electricity meter every 10 seconds to get the three currents. We do a moving average to keep track of fast current changes. The result (largest average current) is available over HTTP API.</p>
<h4 id="charge-controller">Charge Controller:</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">esphome</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">esp8266</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">board</span>: <span style="color:#ae81ff">d1_mini</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Disable logging to be able to use Modbus</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">logger</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">baud_rate</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">ota</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">http_request</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">useragent</span>: <span style="color:#ae81ff">esphome/ESP8266</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">timeout</span>: <span style="color:#ae81ff">10s</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">esp8266_disable_ssl_support</span>: <span style="color:#66d9ef">yes</span> <span style="color:#75715e">#to prevent OTA filing</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id</span>: <span style="color:#ae81ff">http_request_data</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">wifi</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—ssid</span>: <span style="color:#e6db74">&#34;ssid&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">password</span>: <span style="color:#e6db74">&#34;pass&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">web_server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">80</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">uart</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id</span>: <span style="color:#ae81ff">mod_bus</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">tx_pin</span>: <span style="color:#ae81ff">GPIO1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">rx_pin</span>: <span style="color:#ae81ff">GPIO3</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">baud_rate</span>: <span style="color:#ae81ff">9600</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">modbus</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id</span>: <span style="color:#ae81ff">modbus_evse</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">modbus_controller</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">0x01</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_id</span>: <span style="color:#ae81ff">modbus_evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">update_interval</span>: <span style="color:#ae81ff">30s</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">setup_priority</span>: -<span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">sensor</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">template</span> <span style="color:#75715e">#Max phase current, will be written by lambda</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;TokMax&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tokmax</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">#EVSE sensors</span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">set_charge_current</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#ae81ff">holding</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">1000</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">U_WORD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Set Charge Current</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">unit_of_measurement</span>: <span style="color:#ae81ff">A</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">device_class</span>: <span style="color:#ae81ff">current</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">state_class</span>: <span style="color:#ae81ff">measurement</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">vehicle_state</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#ae81ff">holding</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">1002</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">U_WORD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Vehicle State</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">ctrl_bits</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#ae81ff">holding</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">1004</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">U_WORD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Control Bits</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">entity_category</span>: <span style="color:#ae81ff">diagnostic</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">disabled_by_default</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">evse_state</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#ae81ff">holding</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">1006</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">U_WORD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">EVSE State</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">accuracy_decimals</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Manual current setting slider</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">number</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">set_charge_current_input</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">1000</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">value_type</span>: <span style="color:#ae81ff">U_WORD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Set Charge Current (Input)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">unit_of_measurement</span>: <span style="color:#ae81ff">A</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">min_value</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">max_value</span>: <span style="color:#ae81ff">16</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">step</span>: <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">use_write_multiple</span>: <span style="color:#66d9ef">True</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">write_lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      if (x &gt; 0 &amp;&amp; x &lt; 6) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        return 6;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      return x;</span>      
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Switch for turning EVSE on or off. Note the negated function: switch on = EVSE off!</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">switch</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">modbus_controller</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">modbus_controller_id</span>: <span style="color:#ae81ff">evse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">disable_charging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Disable Charging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">use_write_multiple</span>: <span style="color:#66d9ef">True</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">register_type</span>: <span style="color:#ae81ff">holding</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">address</span>: <span style="color:#ae81ff">2005</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">bitmask</span>: <span style="color:#ae81ff">16384</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Template binary sensor for enabling/disabling the whole EVSE system, used for time scheduling to reduce electricity costs</span>
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">template</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Enable</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">enable</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restore_state</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">optimistic</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_on_action</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—switch.turn_off</span>: <span style="color:#ae81ff">disable_charging</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_off_action</span>:
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—switch.turn_on</span>: <span style="color:#ae81ff">disable_charging</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Readouts and automation</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">time</span>:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">—platform</span>: <span style="color:#ae81ff">sntp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">sntp_time</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_time</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Every 30 seconds do readout of max phase current</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—seconds</span>: <span style="color:#ae81ff">/30</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>         <span style="color:#f92672">—http_request.get</span>:
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">url</span>: <span style="color:#ae81ff">http://stevec.local/sensor/tokmax</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">headers</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">Content-Type</span>: <span style="color:#ae81ff">application/json</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">verify_ssl</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">on_response</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>                 <span style="color:#f92672">—lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                        id(tokmax).publish_state(root[&#34;value&#34;]);
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      });</span>                      
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Every 5 minutes do current control</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—seconds</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">minutes</span>: <span style="color:#ae81ff">/2</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>         <span style="color:#f92672">—lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              //Current limits of system
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              const float max_phase_current=20, max_charge_current=16, min_charge_current=6;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              //Only do current control if EVSE is ON
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              if (!id(disable_charging).state) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                //Only do current control if max phase current is too high or charge current setting is reduced (plus offset to prevent corrections under 1A, which have no effect)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                if ((id(tokmax).state &gt; (max_phase_current + 0.5))||(id(set_charge_current).state &lt; max_charge_current)) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  //If max phase current is too high (plus offset)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  if (id(tokmax).state &gt; (max_phase_current + 0.5)) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    //If current is low enough to limit properly
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    if (id(tokmax).state &lt; (max_phase_current + id(set_charge_current).state—min_charge_current)) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      //Reduce current setting by exactly the excess current
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      auto call = id(set_charge_current_input).make_call();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.set_value(id(set_charge_current).state—(id(tokmax).state-max_phase_current));
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.perform();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    } else {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      //Turn off EVSE to cool everything off
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      id(disable_charging).turn_on();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  } else if (id(set_charge_current).state &lt; max_charge_current) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    //Increase current setting by exactly the unused current capacity
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    if ((id(set_charge_current).state—(id(tokmax).state-max_phase_current)) &lt; max_charge_current) {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      auto call = id(set_charge_current_input).make_call();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.set_value(int (id(set_charge_current).state—(id(tokmax).state-max_phase_current)));
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.perform();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    } else {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      //Or set maximum charge current
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      auto call = id(set_charge_current_input).make_call();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.set_value(max_charge_current);
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      call.perform();
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">              }</span>              
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Every 15 minutes turn EVSE back on</span>
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">—seconds</span>: <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">minutes</span>: <span style="color:#ae81ff">/15</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>         <span style="color:#f92672">—if</span>:
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">condition</span>:
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  return id(enable).state;</span>                  
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>               <span style="color:#f92672">—switch.turn_off</span>: <span style="color:#ae81ff">disable_charging</span>
</span></span></code></pre></div><p>This is the main functionality. We set up the Modbus communication with the EVSE controller and prepare the necessary variables to control it. My neighbor did not want to have the whole Home Assistant setup, so the control works via a slider in the inbuilt web server.</p>
<p>The control principle is simple – if the average max current exceeds the permitted maximum, the charging current is set to a lover value. E.g. with 20A limit, if the actual phase current is 22A and the set charging current is 16A, the charging current is reduced by 22-20 = 2A, e.g. to 14A. If there is headroom (a big load has disconnected), the charging current is set higher in the same way. This repeats every 5 minutes.</p>
<p>In extreme cases, where the charging current would have to be reduced under 6A (minimum for the EVSE standard), the charging point is turned off until the next 15 minute interval. This should cool off the fuses enough. Keep in mind that normal  fuses should hold a significant overload for tens of minutes (standard requirement is: blow in less than one hour for 45% overload, over one hour for 13% overload).</p>
<p>All that is left is a simple option to turn the whole thing on or off via a switch in the web server or an API call.</p>
<h2 id="final-notes">Final Notes</h2>
<p>This was intended as an illustration of how to build a safe EV charging point with dynamic current control. There are literally thousands of ways how you could go about achieving this, but the general outline will always be the same:</p>
<p><strong>Measure current coming into your home, compare to limit, set charging current, repeat. Turn off EVSE for 15 minutes, if load is too damn high 😉</strong></p>
<p>This could be thought of as trivial, but there is an important point here: if you buy a ready-made charging point, it needs to dynamically control the charging current! If you buy a “dumb” charging point, you are going to be paying for blown fuses at least some of the time and extra power capacity all the time.</p>
<p>If you found this article useful, you can buy me a beer <a href="https://paypal.me/FranciKopac?country.x=SI&amp;locale.x=en_US">here</a>.</p>
]]></content:encoded></item></channel></rss>