Saturday, 14 November 2026

Solar Build #2: Planning a SANS-Friendly Hybrid Setup (MUST PV18-5048 + Meritsun LFP)

Part 1: Design and planning

Back in June 2015 I documented my first solar install here on the blog (Part 1: The brief overview – Going Solar). I've now started a second build, and this time I wanted to get the design right on paper before touching a single cable. I started with a diagram from ChatGPT. It was a reasonable starting point, but when I checked it against SANS 10142-1 (the South African wiring code) it had some serious gaps. This post covers what I changed and why.

Disclaimer: This is my personal project log, not professional advice. In South Africa a registered electrician has to verify the installation and issue a Certificate of Compliance (CoC). Your insurer will almost certainly ask for it too.


The kit

Component Model Key specs
Inverter MUST PV18-5048 VHM (off-grid hybrid) 5 kW, 48 V, 118 A DC in, 80 A MPPT charger, PV 64–130 V MPPT / 145 V max
Batteries 2 × Meritsun LFP100-48 48 V, 100 Ah (about 5 kWh each, about 10 kWh total), 100 A working current, 15S
Battery breaker VVOKA WJM1-125/2300Z DC-MCCB 125 A, 2-pole, 550 V DC, 20 kA breaking capacity
PV About 2.5 kW of panels About 37 V Voc, about 9 A Isc each
AC surge protection ACDC KM20-40 (already in my DB) 275 V, 40 kA

What the AI diagram got wrong

The ChatGPT diagram had a sensible AC layout (a grid bypass and an interlocked changeover switch). Here's what was missing or wrong:

  1. No PV side at all. It showed no panels, no DC isolator and no DC surge protection.
  2. No earth leakage protection anywhere.
  3. No neutral-earth bond on battery. This is the big one, and I explain it below.
  4. Battery wiring: unequal cable lengths, a confusing extra blue DC cable, and no clear fusing per battery.
  5. Labelling: a "Manual Bypass ATS" (ATS means automatic transfer switch, so the label contradicts itself), and no breaker ratings or cable sizes.
  6. Several separate earth spikes instead of one main earth terminal.

Lesson: AI tools are handy for a first sketch, but check everything against the standard.


What's changed since my 2015 build

2015 build 2026 build
Inverter 5 kVA Chinese off-grid MPPT hybrid, 48 V MUST PV18-5048 VHM, 5 kW, 48 V (still off-grid, no export)
Batteries 4 × 12 V 100 Ah lead-acid deep cycle in series (48 V, ~4.8 kWh, only ~50% usable) 2 × Meritsun 48 V 100 Ah LiFePO4 in parallel (~10 kWh, most of it usable)
PV 4 × 250 W "12 V" panels in series, ~1 kW ~2.5 kW, 3 × 37 V Voc panels per string, several strings in parallel
Design focus Sizing, cost and payback Protection and SANS 10142-1 compliance

Some things haven't changed. Run on solar by day, use the grid at night and fall back to batteries during load shedding. Size the system for what you actually use, and put only the essential loads on the inverter. Both still work.

What has changed: - Lithium instead of lead-acid. I no longer need the 50% depth-of-discharge rule I wrote about in 2015. Lithium cycles deeper and lasts longer, but it needs proper DC protection (that 20 kA breaker) and the correct charge settings for 15S. - The MPPT window instead of "12 V panels". In 2015 I thought of panels as 12 V or 24 V blocks. With MPPT, what matters is the string's open-circuit voltage against the inverter's limit (145 V here), including on a cold morning. - Protection and earthing are designed in from the start. These are the earth leakage unit, the neutral-earth bond on battery, separate neutrals, DC isolators and surge arresters. My 2015 cost table left out the DB and electrical work. This time it's the core of the design. - A correction to my 2015 note on kVA: multiplying kVA by 0.8 is a rough rule. Modern inverters such as the MUST state their rating in watts, so use that figure.


The design

1. PV strings: watch the 145 V limit

The MUST's MPPT range is 64–130 V, but the number that can damage the inverter is the 145 V maximum PV input. Panel open-circuit voltage rises in the cold, so plan for a winter morning:

  • 3 panels × 37 V = 111 V at 25 °C, about 122 V at −5 °C. ✅
  • 4 panels would be about 163 V on a cold morning. ❌ That's above the maximum.

So I'm using 3 panels per string and several strings in parallel. Every string has the same panel model, orientation and tilt.

The combiner box: - One 16 A, 2-pole, DC-rated breaker per string. With 3 or more strings in parallel, a faulty string can be back-fed by all the others. - +/− busbars, then a Type 2 DC surge arrester (a low-voltage PV type), then a 40 A DC isolator, then the inverter. - 4 mm² solar cable per string, and 6 mm² to the inverter.

2. Batteries: busbars, equal cables and a proper DC breaker

  • Both batteries go to +/− busbars with equal-length, equal-size cables so they share current evenly.
  • From the busbars to the 125 A 2-pole DC-MCCB, then into the inverter, using 35–50 mm² cable.
  • The 20 kA breaking capacity matters. Two LiFePO4 batteries can push thousands of amps into a short circuit, and a cheap DIN-rail breaker might not be able to break it.
  • DC breakers are often polarised: the LINE side goes to the battery and the LOAD side to the inverter.
  • If a battery has no breaker on its front panel, fuse its positive lead close to the battery.

The 15S gotcha: My Meritsun serial numbers start with MSP15S, which means 15 cells in series. The pack is fully charged at about 54 V, while many inverter defaults assume 16S. I'm setting the battery type to USER. The values below are to be confirmed with Meritsun: - Bulk about 52.5–53 V, float about 51.5–52 V, cut-off about 45–46 V - Total charge current ≤ 100 A. The MUST can charge at up to 140 A (solar plus AC), which is more than the 125 A breaker can carry.

3. AC side: a separate solar DB and a changeover switch

My existing DB has a 63 A main switch, lights, a 30 mA earth leakage unit and the stove and plug circuits. The solar DB sits about 1 m away.

  • House DB: a 40 A breaker feeds the inverter's AC input (10 mm² cable).
  • Solar DB: inverter output, then a 25 A breaker, then a 30 mA earth leakage unit.
  • Changeover switch: 2-pole (L + N), GRID – OFF – SOLAR, break-before-make.
  • Essential circuits only on solar: lights, the fridge, TV, Wi-Fi and computers. The inverter can supply 22 A (5 kW), so the stove and geyser stay on grid only.

4. Separate neutrals

The grid neutral and the solar neutral stay completely separate. They only meet inside the changeover switch, and every essential circuit has both its L and its N switched over. If you mix the neutrals, earth leakage units trip for no obvious reason and the bonding scheme below stops working.

5. The neutral-earth bond: the part most diagrams leave out

When the grid fails and the inverter runs on battery, its output has no neutral-earth reference. Without that bond, the solar DB's earth leakage unit can't trip on an earth fault. The protection looks fitted but doesn't actually work.

My plan is an N-E bonding relay in the solar DB: - A normally-closed contact, with its coil powered from the grid - Grid live: the coil is energised and the bond is open (the grid supplies the N-E reference) - Grid down: the coil drops out and the bond closes on the inverter side

Check your inverter manual first. If the inverter bonds N-E internally on battery, a relay would give you a double bond.

6. Earthing

There is one main earth terminal in the house DB. The panel frames and rails, battery rack, inverter and solar DB all bond back to it. There's no separate earth spike for the solar side.


Diagrams

[Insert the single-line diagram here. – upload image in Blogger]

[Insert the multi-line wiring diagram here: L, N, PE and DC +/− shown separately. – upload image in Blogger]


Commissioning checklist

  • ☐ Polarity checked on all DC breakers (LINE side to the source)
  • ☐ String voltages measured before connecting the inverter (each one below 145 V)
  • ☐ Inverter battery type set to USER, with the 15S voltages and a charge current of 100 A or less
  • ☐ Earth leakage test on SOLAR with the grid off: it must trip
  • ☐ Bonding relay confirmed open when on GRID
  • ☐ "Dual supply / embedded generation" labels at the meter, both DBs, the changeover switch and the inverter
  • ☐ AC and DC cables in separate trunking
  • ☐ CoC issued by a registered electrician
  • ☐ Checked with the municipality whether the system has to be registered (it's off-grid with no export)

Next up

Part 2 will cover the physical install: mounting the panels, building the combiner box, the battery bay and the first power-up. I'll post photos and the real measured string voltages.

Have you built something similar or spotted something I've missed? Let me know in the comments.

Monday, 13 July 2020

ElastiFlow Netflow monitor on Ubuntu 18.04

Elastiflow installation on Ubuntu 18.04 on Elastic ver 7.


Install Ubuntu 18.04 (see detail right at the bottom of this post with the basic Ubuntu install screenshots)

Once Ubuntu is installed ssh to the box and run the following:

Run sudo -i to be in perm sudo mode

apt update
apt upgrade

Create snapshot here (call it your Ubuntu base install)


sudo -i (if you rebooted since doing the updates)

Run the following:

add-apt-repository -y ppa:webupd8team/java
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
apt install apt-transport-https
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
apt update
apt install openjdk-11-jre-headless
apt install elasticsearch; sudo apt install kibana; sudo apt install logstash


Edit the Kibana configuration file:

nano /etc/kibana/kibana.yml
  • server.port: 5601
  • server.host: "0.0.0.0"
Enable and start the services:

systemctl enable kibana.service
systemctl start kibana
systemctl status kibana


You want to see the highlighted part, then you know that is working:

● kibana.service - Kibana
   Loaded: loaded (/etc/systemd/system/kibana.service; disabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-07-02 09:19:37 UTC; 21s ago
 Main PID: 5432 (node)
    Tasks: 11 (limit: 4915)
   CGroup: /system.slice/kibana.service
           └─5432 /usr/share/kibana/bin/../node/bin/node /usr/share/kibana/bin/../src/cli


If you are running internally with no exposed services, disable the firewall. (or you need to add exclusions):

systemctl stop ufw.service
systemctl disable ufw.service








Test it at this point and you should get the following: 




Leave that as is and go back to the SSH Terminal: (still running as sudo -i)


Edit the elasticsearch config file, make the highlighted changes

nano /etc/elasticsearch/elasticsearch.yml


# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
#
network.host: localhost           
#
# Set a custom port for HTTP:
#
http.port: 9200
#

Enable and start the services:

systemctl daemon-reload
systemctl enable elasticsearch.service
systemctl start elasticsearch.service
systemctl status elasticsearch.service

You should see it saying Running, similar to the Kibana service ..

Give it 2 minutes and then test it..


You should now see this..





And then end up here..




Leave that as it is and head back to the SSH Terminal (still as sudo -i)


Add/Update Logstash plugins: (if you did a default install these file locations should be correct)

Run these one by one….. things to note… some take a while to install and say success updated …..

Some run for a while and say nothing changed… don’t start hacking your install, its all ok… read on..


/usr/share/logstash/bin/logstash-plugin install logstash-codec-sflow
/usr/share/logstash/bin/logstash-plugin update logstash-codec-netflow
/usr/share/logstash/bin/logstash-plugin update logstash-input-udp
/usr/share/logstash/bin/logstash-plugin update logstash-input-tcp
/usr/share/logstash/bin/logstash-plugin update logstash-filter-dns
/usr/share/logstash/bin/logstash-plugin update logstash-filter-geoip
/usr/share/logstash/bin/logstash-plugin update logstash-filter-translate



If you are concerned about the plugins that said nothing installed run this command to see what plugins are install and what versions there are..

bin/logstash-plugin list --verbose


Create snapshot here (call it your Elastic install)


Now we install ElastiFlow: ( still running as sudo -i)

I modified the installs I found on the Internet to install ver 3.5.0.

wget https://github.com/robcowart/elastiflow/archive/v3.5.0.zip
apt install unzip
unzip v3.5.0.zip
cp -r elastiflow-3.5.0/logstash/elastiflow /etc/logstash
cp -r elastiflow-3.5.0/logstash.service.d/elastiflow.conf /etc/systemd/system/logstash.service.d

Edit the Java Virtual Machine config file, change the memory allocation to almost as much ram as you can give the box (mine has 8 gig)

sudo nano /etc/logstash/jvm.options

-Xms6g
-Xmx6g

Edit the piplelines configuration file and add the two highlighted lines, make sure the spacing is exactly the same…

sudo nano /etc/logstash/pipelines.yml

- pipeline.id: main
  path.config: "/etc/logstash/conf.d/*.conf"
- pipeline.id: elastiflow
  path.config: "/etc/logstash/elastiflow/conf.d/*.conf"


Now we need to edit the inputs, still ad sudo -I  edit the appropriate config file, if you are not using Netflow IP4, then just do a directory listing in the folder to find the right file.(or look below I pasted the directory contents)

cd /etc/logstash/elastiflow/conf.d/

nano 10_input_netflow_ipv4.logstash.conf

Change the value to true if you want DNS lookups to be done..then add your internal nameserver..

Environment="ELASTIFLOW_RESOLVE_IP2HOST=true"     
Environment="ELASTIFLOW_NAMESERVER=10.10.10.11"


Further below set the host to 0.0.0.0 to listen to all inputs, unless you only send from one host and want to tie it to that one specific host..then also change the port to whatever port you are sending Netflows on

# Netflow - IPv4
Environment="ELASTIFLOW_NETFLOW_IPV4_HOST=0.0.0.0"
Environment="ELASTIFLOW_NETFLOW_IPV4_PORT=9995"
# Netflow - IPv6
Environment="ELASTIFLOW_NETFLOW_IPV6_HOST=[::]"
Environment="ELASTIFLOW_NETFLOW_IPV6_PORT=52055"
# Netflow - UDP input options
Environment="ELASTIFLOW_NETFLOW_UDP_WORKERS=4"
Environment="ELASTIFLOW_NETFLOW_UDP_QUEUE_SIZE=4096"
Environment="ELASTIFLOW_NETFLOW_UDP_RCV_BUFF=33554432"
# Netflow timestamp options
Environment="ELASTIFLOW_NETFLOW_LASTSW_TIMESTAMP=false"
Environment="ELASTIFLOW_NETFLOW_TZ=UTC"


# sFlow - IPv4
Environment="ELASTIFLOW_SFLOW_IPV4_HOST=0.0.0.0"
Environment="ELASTIFLOW_SFLOW_IPV4_PORT=6343"
# sFlow - IPv6
Environment="ELASTIFLOW_SFLOW_IPV6_HOST=[::]"


Here is the directory listing..

/etc/logstash/elastiflow/conf.d/

Dir…

10_input_ipfix_ipv4.logstash.conf             10_input_sflow_ipv6.logstash.conf.disabled  20_filter_90_post_process.logstash.conf
10_input_ipfix_ipv6.logstash.conf.disabled    20_filter_10_begin.logstash.conf            30_output_10_single.logstash.conf
10_input_netflow_ipv4.logstash.conf           20_filter_20_netflow.logstash.conf          30_output_20_multi.logstash.conf.disabled
10_input_netflow_ipv6.logstash.conf.disabled  20_filter_30_ipfix.logstash.conf
10_input_sflow_ipv4.logstash.conf             20_filter_40_sflow.logstash.conf



Enable and start the services:

systemctl daemon-reload
systemctl enable logstash.service
systemctl start logstash.service


Now at this point it’s a good idea to go to your device that will send Netflows and enable the sending… once that is done go back to your SSH Terminal and run the following command (still as sudo -i)

tail -f /var/log/logstash/logstash-plain.log

It will take a while and start running up a load of things, if you see anything about error….then something did not work as planned..

Now….admittedly… I have no idea where I finally managed to find this file or whether its really needed in this version of elastic, I guess I could do a full new install and see if I leave it out the patterns are downloaded automatically… I found the file somewhere, used SSH to copy it to the Ubuntu machine. If you want the file message me and I can drop it in email, its 1.3 meg, or try without it and tell me if it works 


Copy elastiflow.index_pattern.json file to the home folder of admin_it, then used the command below to create the Kibana Indexes.


curl -X POST http://10.10.10.92:5601/api/saved_objects/index-pattern/elastiflow-* -H "Content-Type: application/json" -H "kbn-xsrf: true" -d @/home/admin_it/elastiflow.index_pattern.json


Almost there, now connect to Kibana Interface

http://(Machine IP Address):5601

Download the 7.5 dashboard from Rob Cowart’s Github page..




Add the Dashboard by importing it, go to Kibana/Stack Management/Saved objects… then on the top right click on import, browse to and select the downloaded file, click on import and it should come back and say success...


By Now in  the tail log you should see something like this…





Give it a few minutes and you should see the flows appear in Kibana under the index patterns.












































A screenshot of a cell phone

Description automatically generated



A screenshot of a cell phone

Description automatically generated



A screenshot of a cell phone

Description automatically generated



A screenshot of a social media post

Description automatically generated



A screenshot of a cell phone

Description automatically generated



A screenshot of a cell phone

Description automatically generated



A screenshot of a cell phone

Description automatically generated