CC Blog Projects Research & Design Hub

Local Isolation

FIGURE 1 The12V gel cell battery allowed me to run the LED light bar at the Eagle's Nest, to test placement and calculate how many lights I would need to cover the entire area.
Written by Jeff Bachiochi

Using the Sun’s Energy

Inspired by Stuart Ball’s recent piece in Circuit Cellar on solar energy basics, I decided to build a low-voltage solar energy system. I talk about the battery and detail how I used the Modbus protocol with RS-485 serial communication for remote monitoring, with the ESP32-based HUZZAH32 Feather microcontroller (MCU).

  • How can I build a low voltage solar energy system?
  • How can I use the Modbus protocol with RS485 serial communication for remote monitoring?
  • What’s a fun project with the HUZZAH32 Feather?
  • HUZZAH32 Feather
  • SN75176

This is my fourth start on this month’s column. I’m not sure what’s going on, but I just can’t pull the trigger, so to speak. So I’ll try something different. I just read Stuart Ball’s article on solar energy (“Solar Energy—Getting Started,” Circuit Cellar issue #395, June 2023) [1]. I’ve used solar power in many projects over the years, and determining the minimum panel/battery size is always a major headache.

Recently, my Scout Troop 96 built a two-story shed (the “Eagle’s Nest”) on our host’s property, to house our camping equipment. The shed has an attached carport where we can park a trailer and can load and unload it under cover. We camp year-round, and sometimes the weather is quite nasty.

There are no utilities on this property, so the building’s interior has no lighting, except for what comes in the small windows. We can move around clumsily during the day, but once it gets dark, you’d better have a flashlight!

I thought that installing some solar equipment might be a great educational experience for the scouts. We’re not talking tons of roof panels and AC lighting, but rather, a low-voltage system that could handle some LED lighting. The simplest system would consist of a solar panel, a charge controller, and a 12V storage battery. But first, let’s step back and look at the building’s layout and what type of lighting would be best.

12V LEDS

Since the system will have a 12V battery, I began my search for some LED panels that would run on 12V. I chose an LED bar with 120 LEDS, which outputs uniform 5,000K/1,100 lumens of light output and rated at 5,000 hours. That is equal to a 75W incandescent light bulb. To be truthful it looks a lot brighter. I suspect that because all of the LEDs are on the same plane, it acts more like a spotlight. It measures 650mA at 12V (that’s 12V x 0.65A = 7.8W).

I’ve got a 12V gel cell hanging around here, which I will use for initially determining what I’ll need. It is rated for 144W-h, so it should run this for 144W / 7.8W = 18 hours, until it completely drains the battery. Since depth of discharge will negatively affect the cycle lifetime, you want to keep the discharge to a minimum, say 50-80%, depending on the battery type. If you were to keep it to 90%, that would give you 2 hours. My experiment will probably not exceed 2 hours, so I’m OK.

FIGURE 1
The12V gel cell battery allowed me to run the LED light bar at the Eagle's Nest, to test placement and calculate how many lights I would need to cover the entire area.
FIGURE 1
The12V gel cell battery allowed me to run the LED light bar at the Eagle’s Nest, to test placement and calculate how many lights I would need to cover the entire area.

I carried the LED lamp and the gel cell (Figure 1) to the Eagle’s Nest for the next phase of determining the strategic placement of these LED units. I wanted to see how many units would be required to illuminate the inside sufficiently, including the entrance, work areas, stairway, and attic storage. After an hour or so of sketching the floor plans and positioning the LED lamp around the area and marking these on the map, I drove home to come up with the drawing in Figure 2.

FIGURE 2
This is the floor plan of the Eagle's Nest. It is used to hold all the scouting equipment for our Troop. With no electricity or Internet access, I wanted to create a functional model of solar energy storage to support our need for interior lighting. Scouts need a safe environment (well lit) to pack or unpack equipment for camping events.
FIGURE 2
This is the floor plan of the Eagle’s Nest. It is used to hold all the scouting equipment for our Troop. With no electricity or Internet access, I wanted to create a functional model of solar energy storage to support our need for interior lighting. Scouts need a safe environment (well lit) to pack or unpack equipment for camping events.

It looks like it will require six LED lamps for the attic, two for the stairs, and six for the bottom floor. I could install each of these with its own light switch, but I decided to use motion detectors instead, to eliminate the possibility of leaving lights on. They are a bit more expensive than mechanical switches, but just might be more helpful if you’re carrying equipment and don’t have a free hand.

If all the lights were on at once, my gel cell would last only 8 minutes! I’ll want at least a couple of hours’ worth of light when we are collecting equipment for an outdoor adventure, or bringing back and cleaning everything before it gets stowed. So, I’ll be shooting for battery storage at least 10 times that of the gel cell. In reality, I think we’re looking at usage in the order of 1 hour a week for meeting nights, or 3 hours a week, if we have a camping excursion.

SYSTEM DESIGN

I’ve got my eye on a 100Ah Lithium Iron Phosphate battery. The charge and discharge temperature specs are quite specific, if you want to get the rated 4,000 charging cycles. The temperature for charging must be above freezing and below 130°F. The discharging temperature is a bit more relaxed at -4°F to 140°F. This is a definite issue for our shed in the winter, because the temperature can be below freezing for much of the time. Fortunately, these batteries can be obtained with heating pads that maintain a proper operating temperature. I’ll be placing the battery inside an insulated, open-top battery box, to reduce heating requirements in the winter, while allowing excess heat to escape during the summer—heat that can build up inside a closed area.

To keep the battery charged, I’m going with two 100W solar panels that will be mounted on the south side of the shed and not the east/west-facing roof. While the potential is for 16A/hour, I’ll be happy with a fraction of that. If we use 10Ah of battery capacity, we would need the panels to produce an average of 12W for 10 hours to totally recharge the battery.

Of course, there are a lot of unknowns here. We have the battery heaters, which can require a few amps to keep the battery warm on cold winter days, and the parasitic current that the system will require to operate. The total system will comprise solar panels, a charge controller, a storage battery, a Bluetooth module for obtaining statistical and historical data, and all the total loads. Besides the high-current cables to deliver power between panels, controller, and battery, there is also a communication cable (Modbus) and a distribution panel for the loads.

COMMUNICATIONS

Bluetooth can up-link data to your phone over short distances. If I want to monitor this system from my home 12 miles away, Bluetooth won’t cut it. Without Internet available, this might not be possible. Wired communication between devices is a protocol known as Modbus; I want to try to tap into that.

Modbus is an open protocol that has become a standard communications protocol in industry. It is now the most commonly available way to connect industrial electronic devices. Modbus is typically used to transmit data from instrumentation back to a controller. It is often used to connect a controller with a remote terminal unit for monitoring. There are versions of the Modbus protocol that use serial lines and Ethernet. The simplest setup would be a single serial cable connecting the serial ports on two devices, a Client (controller) and a Server (device). The most widely used setup is RS-485.

RS-485 supports inexpensive local networks and multi-drop communications links, using differential signaling over a single twisted pair. It is generally accepted that RS-485 can be used with data rates up to 10Mbps or, at lower speeds, distances up to 1,200m. RS-485 drivers use three-state logic, allowing individual transmitters and receivers to be deactivated. The pieces of equipment located along a set of RS-485 wires are interchangeably called nodes, stations, or devices. The recommended arrangement of the wires is as a connected series of point-to-point (multi-dropped) nodes, that is, a line or bus, not a star- or ring-connected network. Star and ring typologies cause signal reflections or excessively low termination impedance.

Ideally, the two ends of the bus will have a termination resistor connected across the two wires. Without termination resistors, signal reflections off the unterminated end of the cable can cause data corruption. Termination resistors also reduce electrical noise sensitivity, due to the lower impedance. The value of each termination resistor should be equal to the cable characteristic impedance (typically, 120Ω for twisted pairs). The termination also includes pull-up and pull-down resistors, to establish fail-safe bias for each data wire, in case the lines are not being driven by any device. This way, the lines will be biased to known voltages, and nodes will not interpret the noise from undriven lines as actual data.

One of the tricks of RS-485 is to have transmitters that can be disabled without affecting the bus. One of the most widely used RS-485 devices is the SN75176. This is a 5V device, but similar devices are now available for 3.3V operation. Refer to Figure 3 for the RS-485 make-up. You’ll see that both transmitter and receiver can be enabled and disabled. The control lines are opposing logic, which means you can tie them together and have the receiver disabled when the transmitter is enabled. This reduces the data load on your UART receiver.

FIGURE 3
One of the first chips to support RS-485 was the SN75176. This 8-pin device supports a bi-directional twisted pair bus, with a TTL transmitter and receiver that can be individually enabled using separate control lines.
FIGURE 3
One of the first chips to support RS-485 was the SN75176. This 8-pin device supports a bi-directional twisted pair bus, with a TTL transmitter and receiver that can be individually enabled using separate control lines.

I bought some 8-pin DIP devices to experiment with. They cost $1-2. You can get modules on Amazon for about the same price that include a micro to automatically handle the control lines for you. They will enable the transmitter whenever there is data coming into the TX input. I chose the hand-wired prototype approach, using the control lines connected to digital I/O. My interface has six lines: power and ground, TX and RX, and TXenable and RXenable. You can see this circuit in Figure 4.

FIGURE 4
Schematic of my prototype Modbus interface. The 6-pin connector goes to the Hazzah32 microcontroller and the 3-pin connector allows this circuit to become just another node on the Modbus twisted pair.
FIGURE 4
Schematic of my prototype Modbus interface. The 6-pin connector goes to the Hazzah32 microcontroller and the 3-pin connector allows this circuit to become just another node on the Modbus twisted pair.
MODBUS

We now have a physical interface for our Modbus “sniffer.” Now let’s look at the Modbus protocol, itself. The protocol calls for devices to be of one of two types. What was once known as Master/Slave is now called Client/Server. The client is the controller or requester of data, and the Server is the responder with data. The core of the Modbus communication is known as the PDU or Protocol Data Unit, and is defined as a function code followed by an associated set of data. The size and contents of this data are defined by the function code, which cannot exceed 253 bytes in size. Originally it is designed to cover four groups, data banks, or address ranges: coils (output bit), discrete inputs, holding registers (output registers), and input registers. Every function code has a specific behavior that servers can flexibly implement, based on their desired application behavior. The PDU specification defines core concepts for data access and manipulation; however, a server may handle data in a way that is not explicitly defined in the specification.

Defined functions include the basic communications for sending or receiving, data or actions. We will only be dealing with five functions in this project, shown in Table 1. You can read the complete Modbus specifications on the Modbus website [2].

For instance, to read a register, the PDU will contain three bytes—the function code 0x03, the starting address of the register of interest (word), and the number of consecutive registers to read (word). Note that some data may require more than one register to be read. The PDU needs two additional pieces of information. It needs to be routed to the correct device. So, every Server is given its own device address (byte). The total packet Application Data Unit (ADU) will begin with this address, followed by the PDU and ending with a CRC (word) to ensure the quality of the packet. Notice this ADU now contains 8 bytes total.

SNIFFING

I’ll be using a HUZZAH32 Feather as my controller. This is an ESP32-based microcontroller by Adafruit. The second serial port (Serial1) will be used to monitor the Modbus. Serial and transmitter/Receiver controls connections are to IO16-19. Because this first project only contains sniffing, we will only be reading Modbus communications. Note: These might be requests from the Client (in our case the Bluetooth module) or responses from the Server (solar controller).

We need to be able to identify the start of a packet. Since the first byte is the device address and not some unique start byte, we must look for a break in the action. We can’t use packet length, other than knowing a packet can’t exceed 256 bytes, since the packet size will vary. We do know the data rate is 9600baud, and a byte requires 1 start bit, 8 data bits, and a stop bit. This means each byte requires 1ms. Silence between transmissions should be about 4 character times or 4ms. Once we see a 4ms break in data transmission, we can assume the next byte received will be the device address.

TABLE 1
The five functions (along with error codes) that will be used in this project. Most communications will be with registers. The last two functions are actions.
TABLE 1
The five functions (along with error codes) that will be used in this project. Most communications will be with registers. The last two functions are actions.

If you refer to Table 1, you’ll see that there are 10 possible function codes that we might find following the device address. This is enough information to begin making some decisions on just what it is we are seeing (sniffing). Figure 5 and Figure 6 show elements of the flow chart of our sniffer application. Most of the possibilities are unique. The most recognizable part of the communication is the silence between packets. So, we’ll start by looking for either a character being received or the amount of time between received characters. At 9600 baud there is about 1ms between characters. Anything longer than 4ms will be considered a break in communication and the start of a new packet. When we see a received character after a break, we call mbInit() to initialize some variables and begin saving the receiver characters in an array ModbusArray[ ].

FIGURE 5 This first piece of the application's flow chart does the data collection and verification.
FIGURE 5
This first piece of the application’s flow chart does the data collection and verification.
FIGURE 6 
Here's where the decisions are made on determining which commands are being sniffed. As suggested by the dotted lines at the bottom, this only shows the request, response, and response error for the Read command. Other commands follow similar paths.
FIGURE 6
Here’s where the decisions are made on determining which commands are being sniffed. As suggested by the dotted lines at the bottom, this only shows the request, response, and response error for the Read command. Other commands follow similar paths.

We want to detect functions in the packet stream, so we can make a call to the appropriate display routines. The first character will always be the device we are addressing. The second character will always be the request/response function. From the function value we can determine which unique sequence of characters to expect. There are two exceptions. Function 0x03 can have two possible sequences—a request or a response. This can be determined by checking for a correct CRC (Cyclic Redundancy Check) value after receiving 8 characters. If checkCRC() comes back with a match ModbusDone = 1, then it must be a requestRead(). If not, then it could be a bad packet, but we’ll assume it is a response. To check this we look at the value in ModbusArray[2]. This should be the number of registers we are responding with. Now we have an expected number of bytes in the packet and after receiving that number we can do a checkCRC() for this packet, and if there is a match we can call responseRead().

The single-byte write command has exactly the same response and request, so we can expect to see this twice for each request. The multiple-byte write is handled the same way as the read request response. The multiple-byte write response will have 8 characters. If the checkCRC() matches after the eighth character, we call multipleWrite(). We need to check the number of bytes to write, ModbusArray[6], to be able to determine the length of this packet. If a checkCRC() fails, we dump any data collected and begin looking for a new packet.

The CRC is a 2-byte value calculated using bit-wise shift and exclusive OR operations of the CRC-16 rules. This can be calculated upon each data byte, or since there are only 256 possible outcomes, a look-up table of precalculated values can be used.

We can display all kinds of information, so to cut down on the output, I use the myDebug value to determine which items are to be displayed. Each bit of this value is used optionally to enable or disable various routines. For instance, you can select to display only the Break durations (time between packets) by setting myDebug = 0x10. Two other possibilities are uninterpreted or interpreted sniffs. An uninterpreted sniff is the actual data of a packet. An interpreted sniff uses the known register addresses and the description of what data is held there. In the case of the solar controller, there are four areas of registers. The System Information area starts at address 0x0000. The Dynamic Control Information area starts at address 0x0100. The Controller Parameter Settings Information area starts at address 0xE000. The Historical Information area starts at address 0xF000.

The Historical Information area requires a bit more explanation. Unlike the three previous areas, which all contain a single word for each register address, the historical address holds 10 registers (words) of information. Today’s data is stored at address 0xF000. Yesterday’s data is stored at address 0xF001, and so on. This data seems to be a record of particular registers in the Dynamic Control Information area. The specific registers are not documented; however, the phone app displays this data with descriptions of the data, so we can guess at these by their description and the actual values at the end of the day.

EXPOSING A SNIFF

For now, we can see the Modbus traffic and interpret what is being asked of the system from the phone application. As stated earlier, it looks like the History stored each day is the data found in the RAM section, at address register 0x10B-0x11F. These are maximum and minimum values collected during a day. Figure 7 shows the application output of registers 0x100-0x109. Like the historical data these registers cover solar panel output, battery status, and load requirements, except these values are showing the real-time data.

FIGURE 7
This display is an interpreted register dump from 0x100-0x109. Note here that these values were produced on the bench with the controller powered by a battery, but with no solar panel, external temperature probe, or load connected.
FIGURE 7
This display is an interpreted register dump from 0x100-0x109. Note here that these values were produced on the bench with the controller powered by a battery, but with no solar panel, external temperature probe, or load connected.

As shown in Figure 8, when close to the Eagle’s Nest, the system can be monitored using the phone app that is using Bluetooth to communicate. With limited BT range and no Internet access, this becomes an issue. Being able to monitor the RS-485 bus is the entry point we need to look into alternative ways of communication. The next step will be to alter the application to allow the query of registers. There is no activity on the bus, unless the phone app makes queries via BT.

FIGURE 8
I've mounted the basic components of the system on the wall beneath the stairs in the Eagles Nest. Note here (clockwise from the upper left) is the MPPT Charge Controller, Modbus distribution, Bluetooth transceiver, and power distribution. External components include solar panels (not connected), Li-Ion battery (+ and - and white Modbus cable).
FIGURE 8
I’ve mounted the basic components of the system on the wall beneath the stairs in the Eagles Nest. Note here (clockwise from the upper left) is the MPPT Charge Controller, Modbus distribution, Bluetooth transceiver, and power distribution. External components include solar panels (not connected), Li-Ion battery (+ and – and white Modbus cable).

I’ll be mounting the solar panels next. The scouts are getting excited to see the work being done here. They have started hanging around now that they can see some progress. It should be up and running by June, just in time for the longest days of the season. Too much to do and so little time! 

REFERENCES
[1] Ball, Stuart. Solar Energy—Getting Started. Circuit Cellar, Issue 395, June 2023, p. 36-40.
[2] Download the current versions of Modbus specifications and implementation guides: https://www.modbus.org/specs.php

RESOURCES
Adafruit | www.adafruit.com
Espressif Systems | www.espressif.com
Modbus | www.modbus.org

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • SEPTEMBER 2023 #398 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
Website | + posts

Jeff Bachiochi (pronounced BAH-key-AH-key) has been writing for Circuit Cellar since 1988. His background includes product design and manufacturing. You can reach him at: jeff.bachiochi@imaginethatnow.com or at: www.imaginethatnow.com.

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Local Isolation

by Jeff Bachiochi time to read: 14 min