errerr
 


date: 16:46:16, December 3, 2024
my ip: 51.38.50.160:80 (richiardone.eu)
your ip: 18.191.97.252:52359 ()
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Welcome, my name is Emmanuel Roberto Richiardone, this is my place on the web.

You can contact me at e(AT)richiardone.eu

My PGP/GPG public key
More about me here

Blog
  Projects
  Docs, Tips & tricks
  Freebsd tips
  GNU/Linux tips


Outside links:
  Photos on Smugmug
  Discogs
  Anobii
  LinkedIn

Other links:
  tollari.org
  linux.studenti.polito.it

login

RSS feed enabled!

  December 2024  
M T W T F S S
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

search with google
here
all the web

. o .
. . o
ooo


proj-sw
multi page
Mitsubishi HVAC managed from Home Assistant using MQTT and ESP32 with WiFiSun, 29 Sep 24
I got installed three Mitsubishi HVAC, and I needed a way to control them from a central point and remotely. I have already an Home Assistant solution, based on custom Debian over a Raspberry Pi 4.
The first idea was to connect the Mitsubishi HVAC to the Home Assistant using two wire to activate them. But then I found a lot of already work done to completely manage the Mitsubishi HVAC using an ESP MCU connected to the internal CN105 serial connector.

The first code and guide I found were from SwiCago. But I have a lot of ESP32 MCU available, that has bigger size but is powered with 5 V available from the CN105, so no need for a powering circuit. Then I came accross the gysmo38 mitsubishi2MQTT project: fantastic! it is based on ESP32 MCU, it includes a local web interface on the ESP to control the HVAC, and has implemented a complete control of the HVAC using a MQTT client over WiFi. So I've used this mitsubishi2MQTT and adjusted Home Assistant on Debian to get the job done.

== LIST OF MATERIALS ==

Prerequisites:
  • A Mitsubischi HVAC with CN105 connector (connected models MFZKT35VG and MSZAP20VGK)
  • An Home Assistant installation over Debian GNU/Linux
  • A 2.4 GHz WiFi network
New materials:
  1. An ESP32 board (for example ESP32 WROOM MCU
  2. A cable with 4 wires and terminated with connector JST PA2.0 5 pin (such as this)
Also, it is needed an Arduino IDE installation with libraries:
  • Board support for "Arduino ESP32 Boards"
  • Libraries: ArduinoJson, WiFiManager, PubSubClient

== SETUP HVAC USING mitsubishi2MQTT ==

  1. Download the ZIP containing last version of mitsubishi2MQTT and uncompress it in the Arduino projects folder.
  2. Connect the ESP32 board to the USB port
  3. From Arduino IDE, open the sketch mitsubishi2mqtt.ino from the folder just created
  4. From Arduino IDE, select a the board ESP32 used (es. ESP32-WROOM-DA), and select the spiffs format option
  5. From Arduino IDE, compile and upload the sketch
  6. If the the ESP32 board is correctly flashed, it creates a WiFi AP mode useful for the setup, with SSID name HVAC_XXXX (XXXX last 4 character MAC address)
  7. Connect to the HVAC_XXXX WiFi network and using a browser go to webpage http://192.168.1.1
  8. It loads a webpage where you can set the SSID and PSK of the final WiFi network you will use to connect to Home Assistant.
  9. Click Save & Reboot. If it fails to connect for some times, the ESP will return to the AP mode for the initial setup. You can debug what's going on during the startup using the serial monitor of Arduino IDE
  10. If it connects to the final WiFi network, check the network to find the IP address associated to HVAC_XXXX (using AP interface, nmap or wireless network watcher)
  11. Open the webpage of the ESP device using the discovered IP (http://)
  12. Set MQTT configuration: IP address of Home Assistant, name of the HVAC, topic (you can leave "mitsubishi2mqtt"), MQTT username and MQTT password. MQTT broker will be installed on the same host that Home Assistant. Do not use space in the name.

Connect the ESP32 device to the CN105 connector using the cable. CN105 has a serial TTL and power 5 V supply.
Pins are in the following order:
1: +12 V  <- do not connect (in MFZKT35VG  model placed at bottom)
2: GND    <- connect to GND of ESP32
3: +5 V   <- connect to 5V of ESP32
4: TX     <- connect to RX of ESP32
5: RX     <- connect to TX of ESP32
I placed the ESP32 device just outside the carter of the HVAC control card.

== SETUP HOME ASSISTANT TO COMMUNICATE WITH mitsubishi2MQTT ==

=== SETUP MOSQUITTO ===

Setup the compatible MQTT broker, that is mosquitto. Then configure Home Assistant to connect to mosquitto.

If not present, install mosquitto service on the Debian system where Home Assistant is running. As root, execute:
root@pi:~# apt-get install mosquitto

Note, the following packets are needed on my system: mosquitto_1.6.12-1, libdlt2_2.18.5-0.4, libwebsockets16_4.0.20-1, libev4.

Configure mosquitto username and password. Replace USER with your MQTT username.
root@pi:~# mosquitto_passwd -c /etc/mosquitto/passwd USER

Setup mosquitto to include login:
root@pi:~# vi /etc/mosquitto/conf.d/default.conf

# add the following text:

allow_anonymous false
password_file /etc/mosquitto/passwd
And restart service.
root@pi:~# systemctl restart mosquitto

=== SETUP MQTT IN HOME ASSISTANT ===

In the Home Assistant configuration file, add the MQTT broker informations. Set IP of broker 192.168.0.123 with your IP of mosquitto; set username and password as set before.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml

# add the following section

[...]
mqtt:
  broker: 192.168.0.123
  client_id: 'hass'
  username: 'USER'
  password: 'PASS'

Using the web interface of Home Assistant, go to Configuration, then Integrations and click MQTT. There is a window where is it possible to "Publish a packet" and "Listen to a topic". Check that the communication between mosquitto, Home Assistant and ESP mitsubishi2MQTT is working.
In the "listen to a topic" field, indicate the wildcard topic
mitsubishi2mqtt/#
and start listening.
The ESP mitsubishi2MQTT should sent periodically a state message.

It is possible to send a query message to the ESP mitsubishi2MQTT, such as (replace NAME-OF-HVAC with name previously set)
mitsubishi2mqtt/NAME-OF-HVAC/state

# you should receive something like

mitsubishi2mqtt/NAME-OF-HVAC/state
{
    "roomTemperature": 21.5,
    "temperature": 20,
    "fan": "auto",
    "vane": "AUTO",
    "wideVane": "|",
    "mode": "off",
    "action": "off",
    "compressorFrequency": 0
}

If that works, good. You now only have to setup an entity for each Mitsubishi HVAC.

=== SETUP HVAC DEVICE IN HOME ASSISTANT ===

To add an entity to control the Mitsubishi HVAC, I added in the configuration file a climate thermostat for each one.
Under climate section add the following subsection for each heat pump. Modify NAME-OF-HVAC with name previously set.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml

[...]
climate:
[...]

  - platform: mqtt
    name: USER-FRIENDLY-NAME
    mode_command_topic: "mitsubishi2mqtt/NAME-OF-HVAC/mode/set"
    current_temperature_topic: "mitsubishi2mqtt/NAME-OF-HVAC/state"
    current_temperature_template: "{{ value_json.roomTemperature }}"
    temperature_command_topic: "mitsubishi2mqtt/NAME-OF-HVAC/temp/set"
    temperature_unit: C
    max_temp: 30
    min_temp: 16
    mode_state_topic: "mitsubishi2mqtt/NAME-OF-HVAC/state"
    mode_state_template: "{{ value_json.mode }}"
    mode_command_topic: "mitsubishi2mqtt/NAME-OF-HVAC/mode/set"
    modes: ["off", "cool", "heat", "dry", "on"]

Restart Home Assistant service (can be done also from webpage).
Add on the web interface a thermostat panel: you now can choose a climate.USER-FRIENDLY-NAME entity. Enjoy

== MQTT TOPIC OF ESP mitsubishi2MQTT ==

For reference reported here
    topic/power/set OFF
    topic/mode/set AUTO HEAT COOL DRY FAN_ONLY OFF ON
    topic/temp/set 16-31
    topic/remote_temp/set also called "room_temp", the implementation defined in "HeatPump" seems not work in some models
    topic/fan/set 1-4 AUTO QUIET
    topic/vane/set 1-5 SWING AUTO
    topic/wideVane/set << < | > >>
    topic/settings
    topic/state
    topic/debug/packets
    topic/debug/packets/set on off
    topic/debug/logs
    topic/debug/logs/set on off
    topic/custom/send custom see
 https://github.com/SwiCago/HeatPump/blob/master/src/HeatPump.h
    topic/system/set reboot

== USEFUL LINKS ==

https://github.com/gysmo38/mitsubishi2MQTT
https://chrdavis.github.io/hacking-a-mitsubishi-heat-pump-Part-2/
https://www.home-assistant.io/integrations/climate.mqtt/
https://www.home-assistant.io/integrations/mqtt#manual-configured-mqtt-items
Home control with local touchscreen, HTTP remote control, analog and digital IOWed, 4 Aug 21
My need was for an unified device to locally and remotely control home and garden. You'll find a lot of stuff based on Raspberry, so I went that way. Device is based on Raspberry Pi 4 with touch screen display and some custom hardware.

About the software platform I choosed "Home Assistant Core", installed on Raspbian Debian on ARM that I know quite well.
The choice has these pros:
  • Good home automation opensource solution
  • Modern solution with integration with anything related to smart home (Philips hue, IKEA TRÅDFRI, Sonos, MQTT, etc)
  • Manually customisable in Python
  • Nice HTTP interface
  • Customizable to present sensor data, action button and historic view
  • Possibility to build scene and automation mechanisms to activate action upon any conditions
  • Possibility to define zones (area)

== LIST OF MATERIALS ==

The Rasperry Pi
The interface board
  • Stripboard sized 31x26 holes double sided, hole distance 2.54mm (mine is 90x70mm)
  • Female header connector 2.54mm, we need minimum two lines of 20 pitch
  • Some female header connector 2.54mm for the wire connection to the male pin headers
  • Some male pin header connector 2.54mm, one of 40 pin is enough.
  • 4 pcs 3-pin screw connection terminal block
  • 3 pcs 2-pin screw connection terminal block
  • 2 pcs fuse holders
  • Fuse 0.5 A
  • Fuse 1 A
  • MCP3008 microchip analog to digital 2x8 DIP
    https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf
  • 4N35 optocoupler 2x3 DIP
  • 2pcs 1N5711 Schottky diode
  • 5pcs Resistor 1k Ohm
  • Resistor 2k Ohm
  • Resistor 4.7k Ohm
  • 3pcs Resistor 10k Ohm
  • 2pcs resistor 470k Ohm
  • Variable resistor aka precision potentiometer, from 0 to 10k Ohm
  • Capacitor 10uF
  • Capacitor 470pF
  • Some isolated wires AWG24 of different colors
  • 2pcs distance bolt M2.5 with screw, length 12mm + 6mm

Sensors and actuators
For the boxing
Tools needed
  • Soldering iron with sharp tip
  • Tin soldering 0.5
  • Electrician's scissors
  • Cutter
  • Screwdriver Philips and flat
  • Small flat screwdriver
  • Black marker pen
  • Internet connection
  • Some coffee and beer

=== HARDWARE SETUP ===

The Raspberry Pi 4 is fixed on the back of touchscreen display 7". The display is connected to the Pi using his DSI display flat cable.
There is a custom board with some components, IC, fuses and screw connectors, fixed over the Raspberry Pi 4 and directly connected on the GPIO header.
The connectors represent the external interface, where are attached input devices (sensors and contact) and output control using a relay board. The external interface has the following specification:

OUTPUTS
- n.4 isolated digital output using a ready board including optocoupler and relay with both N.O. and N.C (max 10A 250VAC). My usage will be to control a boiler, a well pump, an irrigation valve, and some lights.

INPUTS
- n.1 1-wire protocol interface on 3.3V, can manage a number of sensors connected on the bus identified by serial ID. My usage will be to connect two temperature sensor.
- n.1 I2C protocol interface on 3.3V, can manage a number of sensor connected on the bus identified by programmed ID. My usage will be to connect a humidity/pressure/temperature sensor.
- n.3 Analog input, reading values in voltage, powered at 3,3V. My usage will be to connect two AC power sensor and a water pressure meter.
- n.1 Digital input, optoisolated with variable resistor, input is high when input is closed to 5V. My usage will be to connect a boiler status indicator.
- n.2 Digital input, protected with schottky diode, with input that have to go from GND to 5V and back. My usage will be to connect a hall water flow meter generating a square wave.

POWER AVAILABLE
- The available voltages are 3,3V and 5V, depending on the input type.
- Total maximum current allowed is 0.5A for 3,3V and 1A for 5V, they are fused.

NOTE ON I2C
- Using a Pi version 4, on the DSI cable is passing video combined with touch commands using I2C protocol with address 0x38.
- The I2C used is dedicated and is leaving free the I2C on the GPIO header.

== CALCULATING ELECTRIC POWER ==

I made an approximative calculation about needed current to size correctly the power supply.
For the 5V I divide the power supply line for the Raspberry Pi 4 and for the external interface, so that I am using the Raspberry internal circuitry and fuse to protect itself and the display, and a new fuse for the sensors and devices.
For the 3.3V I use the internal Raspberry Pi 4 regulator but I add a new fuse toward external devices.

 Raspberry Pi 4 		700mA @ 5V
 7" touchscreen display  	550mA @ 5V
 4 channel relay board		each relay when activated 60mA @ 5V,
                                near 0 otherwise. Total from 0 to 240mA
 1-wire pullup resistor		1mA @ 3.3V
 1-wire temperature sensor	2* 1mA @ 3.3V
 I2C humidity/bar/temp sensor	1mA @ 3.3V
 Analog to digital circuit	1mA @ 3.3V
 AC power sensor (n.2)		<1mA @ 3.3V
 Water pressure meter		<1mA @ 5V
 Digital input circuits		<10mA @ 5V
 Hall water flow meter 		<10mA @ 5V

Length of input sensor lines
The length of input sensor lines depends mainly on the bus caracteristic and kind of wire.
Expecting to use UTP cable with AWG24 (0.5 mm2) wires, the voltage loss of an input sensor that is consuming 10mA placed with lines 50 meters long is about 0.1V.
For the 1-wire temperature sensor the bus length on this kind of wire still works 50 m away. 1-wire should use a star topology when using long wire wire more than one sensor.
If needed, it could be necessary to add a low value resistors (under 100Ohm) on the data wire near the sensors to prevent ringing of signal.

The Raspberry Pi 4 internal fuse should allow 1250 mA + at least 45 mA from the GPIO header 3.3V
The external fuse for 5V should allow 500 mA. So I choosed for a 1 A.
The external fuse for 3.3V should allow 45 mA. So I choosed for a 0.5 A.

Summing all, the power supply should deliver at least 9W.

== OUTPUT ACTUATORS ==

Devices commands (output GPIO + relay)
- 4 channel relay board with optocoupler and indicator led
(I am in fact using an 8 channel board because I have that one available, but connect only 4 relays)
Used to control:
  • Heating boiler activation, manual or automatic (thermostat)
  • Well pump command
  • Irrigation valve command
  • Lights command

If it's the case REMOVE JD-VCC to VCC jumper from the board. This jumper connects the input VCC with the relay VCC supply: we are using VCC of 3.3V for GPIO connections and 5V for relay supply. The GND is connected only with the 5V supply, NOT toward the Raspberry GPIO.
To activate the relay coil, the gpio should go to 0 (GND).
See this relay board as sample schematic reference
sample relay schematic
relay

== INPUT SENSORS ==

= Internal temperature board =

Nothing to be done externally of the board.

= 1-wire data protocol =

Works on 3 pin: VCC, GND, DQ
Pull-up resistor 4.7k Ohm

4.7k between positive and data wire protocol
positive to the +3.3

1wire

Used for:
- Outdoor temperature sensor DS18B20
Temperature range -55°C e +125°C
Power supply +3 - +5.5Vdc , negative ground

Cable length should be maximum 10 meters; 1-wire protocol is capacitive, so don't use shielded cables to ground. More sensors can be added in parallel and shares the same pull-up resistor.
1-wire on Raspberry Pi 4 uses as default the pin 7 - GPIO 4
1-wire components

= I2C bus =

Works on 4 pin: VCC, GND, SCL, SDA Directly connected to the Raspberry GPIO header. Using only sensors locally placed with short wires. Used for:
- Sensor BME280
Indoor temperature, humidity, barometer sensor (I2C)

I2C uses on Raspberry Pi 4 the pin 3 - GPIO 2 for SDA and pin 5 - GPIO 3 for SCL. Works on 3.3V.
bme280 components

= Analog inputs =

The Raspberry Pi 4 has only digital GPIO, as an input you can measure if the pin is connected to a 3.3V or 0V, no intermediate values are readeable. The analog inputs are based on a MCP3004/MCP3008 chip, measure voltage levels from 0 to 3.3V. The chip is connected to the Raspberry using SPI bus.
My circuit can manage 3 inputs: n.2 AC current consumption and n.1 water pressure.

MCP3008 Analog to Digital converter

Used for:
- AC current consumption with sensor SCT-013-30, up to 30A that corresponds to 1V.
The sensor includes burden resistor, and comes with two wire connection on 3.5 audio jack (L and K). The AC wire to be measured is one, so the hot wire OR the neutral wire, never both.

As the voltage output is a sine wave corresponding of the AC current, and is centered on 0V, I need to adjust it to be readeable from the MCP3008.
Using the SCT013-030 30A model, the maximum 30A is 6.5 kW on 220 VAC line, and outputs 1V RMS on the sensor. 1V RMS is 1.414 Vpp, so on a oscilloscope between the L and K wires you will see a wave going from -1.42V to +1.42V if you measures a load consuming 6.5 kW at 220VAC. The scale is linear, so i.e. you see a wave between -0.21V to +0.21V measuring a load consuming 1kW at 220VAC.

The MCP3008 measures positive voltage values, and the range is from 0V to 3.3V as it is powered at 3.3V. I need a simple voltage divider to get a reference voltage. Dividing the half of 3.3V is alright as it is +1.65V, so that the measured sine wave will go from +0.23V to +3.07V (+1.65 -1.42 and +1.65 +1.42), a range that can be easily read from the MCP3008.

Note: For the AC load I really need only to measure only peak value. I evalutated using a rectifier circuit with diode and capacitor, but the input signal can have very low amplitude so it's not a good option. I could use a precision rectifier introducing an operational amplifier. But finally I decided to not modify the wave more than changing the reference voltage and to work on software side, to simplify and more flexibility on the board circuit.

circuit_ACsensor

- Water pressure sensor for home distribution pressure that should be 3 bar (0.3 MPa (Mega Pascal))

The sensor I choosed has following specs:
Max. 0.5 MPa = 5 bar
Powered at 5V
Thread G1/4
Reading value: 0-0.5 MPa
Maximum value: 1.5 MPa
Damaging value: 3.0 MPa
Temperature: 0-85 C
Output Voltage: 0.5V = 0 MPa, 4.5V = 0.5 MPa

The sensor has 3 pin connection: VCC, GND, analog voltage.

The sensor works with +5V, so I need some voltage divider to match the 3.3V required for the MCP3008. The analog voltage ranges approximely from 0.5V to 4.5V. It is needed a simple voltage divider 2:1 to match the maximum 3.3V voltage reading of MCP3008 and GPIO, so I put a 2K / 1K Ohm on the analog voltage pin.
Note that some 5V power supply are not exactly this value, but some more. For example 5.5V; in that case, the voltage divider 2:1 with an input of 5.5V gives 3.7V. But it's not an issue with the maximum input voltage of the MCP3008, as the sensor output at max pressure 0.5 MPa (5 bar) is 4.5V, that is 3V after the voltage divider.

circuit_water_sensor

SPI uses on Raspberry Pi 4 the pin 19 - GPIO 10, pin 21 - GPIO 9, pin 23 - GPIO 11 and pin 24 GPIO 8.
analog input circuit components

= Digital inputs =

The Raspberry Pi GPIO are 3.3V based. The inputs I am using are 5V based, so for powering the sensor it's not an issue, but some work has to be done to adapt to the Pi GPIO input.
Remembering that all the Raspberry inputs are digital, so they can read 0V or 3.3V, there are some alternatives:
  1. when using sensor that generates a square wave between 5V and 0V, it can be used a simple circuit with a protection fast diode;
  2. when reading a signal that is closed to 5V or is open (floating), it can be used a optocoupler circuit;
  3. when reading a signal that is closed to 3.3V or is open, it can be used GPIO directly.

I implemented the solution 1. and 2., to be more generic and have some degree of protection.

Fast diode input circuit

Needed:
- Schottky diode 1N5711
- Resistors 10k, 1k

schottky high
schottky low

Schottky diode
I am needing a schottky diode for the fast switching speed. I am working with low voltages so there are no inconveniences.
Hereafter you can see the difference between using a diode 1N4001 and a Schottky 1N5711 as seen on an oscilloscope.

Step using general purpose diode:
general purpose diode general purpose diode 2

Step using 1N5711 diode:
schottky diode schottky diode 2

Used for:
- Hall effect water flow meter sensor (pulse)

The sensor works with 3 pin: VCC, GND, pulse
The sensor is pulled to ground to signal a pulse and float high to the external voltage.

diode input circuit components

Optocoupler input circuit

The optocoupler circuit has a variable resistor on the base to filter noise inputs and trigger the optocoupler transistor for some degree of input signals. It has to be regulated after input line installation.

- 4N35 chip
- Resistors
- Capacitor
optocoupler high
optocoupler low

In the circuit diagram the variable resistor is the 1k between the optocoupler and GND with the capacitor in parallel. The circuit shown set the GPIO input to 3.3V when the switch is opened.

On the board construction, for extra flexibility I put the GND side of the eccitating LED (pin 2) on a input connector, and added a jumper on the board.
This way I can close the line to 5V or close it to GND, according to the jumper and wire setup.
Moreover, I have the possibility to connect the line before and after the LED in the 4N35 chip toward an external powered line as input, removing the jumper.

Used for:
- Generic input, actually a simple switch closed on signalling boiler event

optocoupler components

== OUTPUT AND INPUT BOARD ==

Here is a schematic of the board:
board schematic
And finally the board looks like this:

board 2 board 3
Final board:
board 4 board 5

== MECHANICAL ASSEMBLING ==

Follow these steps:
  1. Make two hole in the strip board where the Raspberry Pi has the two bottom holes.
  2. Labeling with marker
  3. Assembling over LCD touscreen
  4. Putting over raspberry pi some heat dissipators
  5. Put screw on the rasp header
    n.2 distance bolt M2.5 with screw, length 12mm + 6mm
  6. Connect flat cable of LCD screen
  7. Put last 2 screw in the holes of the strip board
  8. Connect 5V and GND wire for LCD screen

Putting it over the Raspberry Pi
attach 1 attach 2
Connecting display
attach 3 attach 4
attach 5 attach 6

Cabling
powering 1 powering 2
Cabling 1 Cabling 2

Boxing
ABS box with size 200 x 120 x 75 mm , you'll find it in beige or black variant.
Modify the box to make a display support and making some vent holes and cable passage.

Boxing 1 Boxing 2
Boxing 3 Boxing 5
Boxing 7 Boxing 8

== SUMMARY OF GPIO ==

pin 3 - GPIO 02 - i2c bus SDA
pin 5 - GPIO 03 - i2c bus SCL

pin 7 - GPIO 04 - 1-wire 	externally pullup'd

pin 11 - GPIO 17 - digital input 3 closed to 5V or closed to GND
                                   (according to the jumper, GPIO goes low;
                                   if opened, GPIO goes high)
pin 13 - GPIO 27 - digital input 1 	GND or 5V
pin 15 - GPIO 22 - digital input 2 	GND or 5V

pin 19 - GPIO 10 - SPI MOSI 	analog input 1 (from 0 to 4.5V), analog input 2 and 3 (from -1,5V to +1,5V)
pin 21 - GPIO 09 - SPI MISO 
pin 23 - GPIO 11 - SPI CLK
pin 24 - GPIO 08 - SPI CE 

pin 35 - GPIO 19 - digital output 4 (relay NO, NC)
pin 37 - GPIO 26 - digital output 3 (relay NO, NC)
pin 38 - GPIO 20 - digital output 2 (relay NO, NC)
pin 40 - GPIO 21 - digital output 1 (relay NO, NC)

=== OS BASE SETUP ===

Starts from raspbian image.
I started with version 10.7 Buster, but later I add testing repository (Bullseye 11) to fix Python 3.8 requirement (I installed 3.9.1). See software installation part about it.

The initial setup is not covered in this guide. We need a very small installation of armbian with a read-only root partition and writable home. We start without any graphical interface, I will install a simple window manager hereafter.
Some notes about the base setup are reported hereafter.

Partitioning with read only root
/ is ro		 size ~6 GB
/boot is ro 	 size 256 MB
/home is rw	 size the rest of the microSD (in my case ~24 GB)
Note: the partitions should be aligned for the microSD to maximise leveling on the read/write partition, considering first 4MiB and so on.

Note: all following setup commands are done from root (i.e. "su -" or "sudo su" )
As we are in readonly filesystem, before anything mount as readwrite:
root@pi:~# mount -oremount,rw /
root@pi:~# mount -oremount,rw /boot
tmpfs /tmp
cd /var
ln -s /tmp log
ln -s /tmp tmp

root@pi:~# vi /etc/fstab

proc            /proc   proc    defaults          0       0
/dev/mmcblk0p1  /boot   vfat    defaults,ro  0       2
/dev/mmcblk0p2  /       ext4    defaults,ro  0       1
/dev/mmcblk0p3  /home    ext4   defaults,noatime        0       0
tmpfs           /tmp    tmpfs   nosuid,nodev,mode=1777,size=400M         0       0
fix some temporary dir
cd /var
rm -R log
rm -R tmp
ln -s /tmp log
ln -s /tmp tmp
Final setup is something like this
root@pi:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       5.3G  2.3G  2.8G  45% /
devtmpfs        805M     0  805M   0% /dev
tmpfs           934M     0  934M   0% /dev/shm
tmpfs           934M  8.5M  926M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           934M     0  934M   0% /sys/fs/cgroup
tmpfs           200M   52K  400M   1% /tmp
/dev/mmcblk0p3   24G   45M   23G   1% /home
/dev/mmcblk0p1  253M   54M  199M  22% /boot
tmpfs           187M     0  187M   0% /run/user/1000

I have a user called "user", plus the root account.

= Debian testing Bullseye =

On Buster I have some issue with matchbox, midori and python versions.
I opted to add Bullseye version 11 repository in apt, adding following lines:
root@pi:~# vi /etc/apt/sources.list

deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
deb http://raspbian.raspberrypi.org/raspbian/ testing main contrib non-free rpi
Upgrade with commands
root@pi:~# apt-get update
root@pi:~# apt-get upgrade
root@pi:~# apt-get dist-upgrade
root@pi:~# apt-get upgrade
root@pi:~# apt-get clean
Take some time. Choose upgrade settings according to your preferences.

I had to solve some kept-back packages and purge libc6-dev for conflicts:
root@pi:~# apt-get purge libc6-dev
root@pi:~# apt-get --with-new-pkgs upgrade

Update eventually installed pip modules
root@pi:~# pip3 list --outdated --format=freeze | grep -v '^-e' | cut -d = -f 1  | xargs -n1 pip3 install -U

After that we have installed raspbian 11 Bullseye, along with python3.9.1

=== ENVIRONMENT CONFIGURATION ===

Note: all following setup commands are done from root (i.e. "su -" or "sudo su" )
As we are in readonly filesystem, before anything mount as readwrite:
root@pi:~# mount -oremount,rw /
root@pi:~# mount -oremount,rw /boot
Let's load at boot io modules, uncommenting
root@pi:~# vi /boot/config.txt

dtparam=i2c_arm=on
dtparam=spi=on
dtoverlay=spi0-1cs
dtoverlay=w1-gpio,gpiopin=4

To rotate display if necessary, uncomment line:
lcd_rotate=2

You also need the following line in /etc/modules
root@pi:~# vi /etc/modules

i2c-dev

== HOME ASSISTANT ==

Home Assistant is installed manually, as a Python 3 virtual env using a "homeassistant" user and group.
I follow the manual guide here https://www.home-assistant.io/docs/installation/raspberry-pi/ but installed it to self home in /home/homeassistant instead of /srv/homeassistant, because in my setup /home is on the only writable partition.

Still as root, install required libraries
root@pi:~# apt-get install python3 python3-dev python3-venv python3-pip 
root@pi:~# apt-get install libffi-dev libssl-dev libjpeg-dev zlib1g-dev 
root@pi:~# apt-get install autoconf build-essential libopenjp2-7 libtiff5

I was unable to build inside the venv the RPi.GPIO pip module, so I install it from apt repository
apt-get install python3-rpi.gpio

Create user homeassistant and folders
useradd -rm homeassistant -G dialout,gpio,i2c
Set virtual env. I uses the flag "--system-site-packages" because I was unable to build inside the venv the RPi.GPIO pip module.
sudo -u homeassistant -H -s
cd /home/homeassistant
python3 -m venv . --system-site-packages
source bin/activate
The prompt changes to (homeassistant) homeassistant@raspberrypi:~ $

Install packages. It will take some time.
python3 -m pip install wheel
pip3 install homeassistant
Start home assistant for the first time. It will take some time because it installs required pip3 packages.
hass
Check to be able the reach the webpage at address. Do nothing for now.

http://RASPBERRYPI_IP_ADDRESS:8123

Check using another terminal that is not installing depencies anymore, i.e.:
root@pi:~# ps -fax

 8142 pts/1    S      0:00  |   _ sudo -u homeassistant -H -s
 8143 pts/1    S      0:00  |       _ /bin/bash
 8402 pts/1    Sl+    0:07  |           _ /home/homeassistant/bin/python3 /home/homeassistant/bin/hass
 1177 pts/2    Ss     0:00  _ /bin/bash
22206 pts/2    R+     0:00      _ ps -fax
Press Ctrl-C in the command line to exit hass

Create the service file to start home assistant at boot:
root@pi:~# cd /etc/systemd/system/
root@pi:/etc/systemd/system# vi home-assistant.service

[Unit]
Description=Home Assistant
After=network.target

[Service]
Type=simple
User=homeassistant
Environment=VIRTUAL_ENV="/home/homeassistant"
Environment=PATH="$VIRTUAL_ENV/bin:$PATH"
ExecStart=/home/homeassistant/bin/hass -c "/home/homeassistant/.homeassistant"

[Install]
WantedBy=multi-user.target
Now you will need to restart the systemctl and read the file with the following commands
root@pi:~# systemctl --system daemon-reload
root@pi:~# systemctl enable home-assistant
root@pi:~# systemctl start home-assistant
Verify
root@pi:~# systemctl status home-assistant
Home assistant logfile is located here:
less /home/homeassistant/.homeassistant/home-assistant.log

== LOCAL TOUCHSCREEN USER INTERFACE ==

Install a minimal window manager, Matchbox, intended for mobile devices and that only shows one window at a time.
root@pi:~# apt-get install matchbox
Install a fast browser, I choosed midori
root@pi:~# apt-get install midori
Install some required Xorg utilities
root@pi:~# apt-get install x11-xserver-utils xinit
root@pi:~# adduser user video
Create a xinit configuration file in user home directory to start window manager and browser
root@pi:~# vi /home/user/.xinitrc

#!/bin/sh

/usr/bin/xset -dpms 
/usr/bin/xset s off 
/usr/bin/xset s noblank

/usr/bin/matchbox-window-manager -use_cursor no -use_titlebar no &
/usr/bin/matchbox-panel --size 20 --orientation north --no-menu --no-session &
/usr/bin/mb-applet-launcher /usr/share/pixmaps/matchbox-keyboard.png /usr/bin/matchbox-keyboard &
/usr/bin/midori -a http://127.0.0.1:8123/
Allow xinit to start as an user from command line
root@pi:~# vi /etc/X11/Xwrapper.config
Modify allowed_users to:
allowed_users=anybody
In start xinit at startup as user "user" using /etc/rc.local
root@pi:~# vi /etc/rc.local

/bin/su user -c /usr/bin/xinit &
exit 0
matchbox-keyboard has an xml file to configure the keyboard layout. The included ones from repositories are too bad.
I started from the one shared from JimmyN here

I made some modification on my keyboard file. You have to place the file in the .matchbox user folder as file keyboard.xml .
You can download my configuration keyboard.xml here

Check that the graphical installation works using
su user -c xinit
You should see the Midori browser with automatic login in Home Assistant, and a top bar with on the left a keyboard icon and on the right a clock.
Touching the keyboard opens the on screen virtual keyboard, touching it again hides the keyboard. Here are two screenshot made with scrot.

homepage 1 homepage 2

I will set autologin for local access to web interface. You do it from the terminal editing the main configuration file.
Set autologin for local access to HTTP interface from localhost.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml
Add following configuration block:
# autologin if one user
homeassistant:
  auth_providers:
    - type: trusted_networks
      trusted_networks:
        - 127.0.0.1
        - ::1
      allow_bypass_login: true
    - type: homeassistant

Setup some settings in both the webpage of home assistant and command line. For simplicity I do it from external PC (not on local graphic user interface).
Accessing the page for the first time will create one user (the first one is an administrator) and a wizard.
http://RASPBERRYPI_IP_ADDRESS:8123

In my setup, first user (and administrator) will have username admin

Graphically, I setup Home Assistant with two panels: the first one is the realtime main operative window; the second one has some historical diagnose and system informations.

== DIGITAL INPUT AND OUTPUT ==

On/off Digital Input and Digital Output are rapidly set in the Home Assistant configuration file. Note that the number ports are GPIO BCM indexes, not pin.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml
Add following configuration blocks:
# Digital Input
binary_sensor:
  - platform: rpi_gpio
    ports:
      17: DI3 Boiler Alert
    invert_logic: false

  - platform: rpi_gpio
    ports:
      22: DI2 Free
    invert_logic: true

# Digital Output
switch:
  - platform: rpi_gpio
    invert_logic: true
    ports:
      21: DO1 Boiler
      20: DO2 Outdoor Lights
      26: DO3 Light outside the gate
      19: DO4 Water Pump

= Digital Input used for Water Flow Counter =

Digital Input 1 (DI1_Water_Flow_Counter) is used as a pulse counter. The specifications of my sensor says it can measure from 1 L/min to 30 L/min . The pulse frequency to flow rate is: frequency (Hz) / 7.5 = flow in L/min .

Moreover using the oscilloscope I saw that the minimum steady value (high or low) was more than 2 ms, and with a duty cyle of 50%. Checking with maths, the maximum frequency can be calculated as 30 L/min * 7.5 = 225 Hz , so the minimum period declared is 1/225 Hz = 0.0044 s = 4.4 ms . So the declared minimum steady value is 2.2 ms, that is corresponding with practical measures.
Each seconds there should be a maximum of 7.5 * 30 = 225 square waves, and 1 L corresponds to 450 pulses.
The rpi_gpio has a bouncetime of ms. It is not required to campionate completely the signal, but only high and low values, so 2 ms is enough.

In Home Assistant, the statistics counter is incremented both when value is high and was low, and is low and was high, so the counter has to to be divided instead by 7.5 * 2 = 14.
The maximum value of the counter is the daily one, that can reach a maximum of 24*60*30*450 = 19,440,000 pulses, that is lower than the maximum int value in Python (2147483647).

I first tried to configure the flow sensor calculation completely in Home Assistant, using the following configuration blocks
root@pi:~# /home/homeassistant/.homeassistant/configuration.yaml

binary_sensor:
  - platform: rpi_gpio
    ports:
      27: DI1 Water Flow Counter
    bouncetime: 2

sensor:
  - platform: statistics
    entity_id: binary_sensor.DI1_Water_Flow_Counter
    name: "Water Flow Daily Count"
    sampling_size: 10000000
    max_age:
      hours: 24

  - platform: statistics
    entity_id: binary_sensor.DI1_Water_Flow_Counter
    name: "Water Flow Second Count"
    sampling_size: 500
    max_age:
      seconds: 1

  - platform: template
    sensors:
      water_daily_usage:
        friendly_name: Water Daily Usage
        value_template: >-
          {{ ( states('sensor.water_flow_daily_count') | float / 900 ) | round(0) }}
        unit_of_measurement: 'L'
        icon_template: hass:water

  - platform: template
    sensors:
      water_flow_usage:
        friendly_name: Water Flow Usage
        value_template: >-
          {{ ( states('sensor.water_flow_second_count') | float / 14 ) | round(0) }}
        unit_of_measurement: 'L/min'
        icon_template: hass:water

After doing that and made some testing, I found the shown values were very different from truth. I believe that this solution with statistics on binary_sensor is not fast enough and was losing counts.
Python sleep() and time() functions are based on OS accuracy; on a non-realtime Linux kernel like my case, the minimum sleep interval is lower than 1 ms but not deterministic, so enough for my purpose.

So I evaluated to create a custom integration for that, but it was too complicated over an external simple python script. I'll propose a simple Python script running from Debian. The script has to always run as a service and communicates with Home Assistant using two temporary files, because I need to always check the square wave to gives near instant value and daily counter.
The script is updating values with an interval of 10 seconds, writing some file in temp filesystem to be read from Home Assistant. An update longer than 1 second helps me compensate the delay introduced by file handling.
I checked sensor counting and correctness of water flow calculation, and seems to be realistic.

Install Python schedule library
root@pi:~# pip3 install schedule
Create a script:
root@pi:~# vi /home/homeassistant/water_flow.sh


#!/usr/bin/python3
# Raspberri Pi - Hall effect Water Flow counter on GPIO
# pip3 install rpi_gpio schedule
# http://richiardone.eu

import RPi.GPIO as GPIO
import time, sys, schedule

FLOW_SENSOR = 27
UPDATE_INTERVAL = 10
FILE_OUT_INSTANT = '/tmp/water_flow.instant'
FILE_OUT_DAILY = '/tmp/water_flow.daily'

GPIO.setmode(GPIO.BCM)
GPIO.setup(FLOW_SENSOR, GPIO.IN, pull_up_down = GPIO.PUD_UP)

daycounter = 0
lastcount = 0

def countPulse(channel):
   global daycounter
   daycounter = daycounter+1

def resetDaily(job):
   global daycounter
   daycounter = 0

GPIO.add_event_detect(FLOW_SENSOR, GPIO.RISING, callback=countPulse, bouncetime=2)
schedule.every().day.at("00:00").do(resetDaily, '')

while True:
   lastcount = daycounter    
   time.sleep(UPDATE_INTERVAL)
   lastcount = daycounter - lastcount
   with open(FILE_OUT_INSTANT, 'w') as file:
      file.write(str(round(lastcount/UPDATE_INTERVAL/7.5, 1)))
   with open(FILE_OUT_DAILY, 'w') as file:
      file.write(str(round(daycounter/450, 1)))
   schedule.run_pending()

Set permission:
root@pi:~# chown homeassistant:homeassistant /home/homeassistant/water_flow.sh
root@pi:~# chmod +x /home/homeassistant/water_flow.sh
Create a systemd service:
root@pi:~# vi /etc/systemd/system/water_flow.service


[Unit]
Description=Water Flow Counter
After=multi-user.target

[Service]
Type=simple
User=homeassistant
ExecStart=/home/homeassistant/water_flow.sh

[Install]
WantedBy=home-assistant.service

Now you will need to restart the systemctl and read the file with the following commands
root@pi:~# systemctl --system daemon-reload
root@pi:~# systemctl enable water_flow
root@pi:~# systemctl start water_flow

Add in configuration.yaml file:
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml
the following block:
sensor:
  - platform: command_line
    name: Water Flow Instant Counter
    command: /bin/cat /tmp/water_flow.instant
    unit_of_measurement: "L/min"
    scan_interval: 10

  - platform: command_line
    name: Water Flow Daily Counter
    command: /bin/cat /tmp/water_flow.daily
    unit_of_measurement: "L"
    scan_interval: 60

= Board status: temperature, uptime, system load, memory =

Internal temperature can be read from command line (the value has to be divided by 1000):
root@pi:~# cat /sys/class/thermal/thermal_zone0/temp
To use the internal temperature I use Command Line integration. You need to add the following to configuration.yaml
 
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml
Add following configuration block
 
sensor:
  - platform: command_line
    name: Board Temperature
    command: /bin/cat /sys/devices/virtual/thermal/thermal_zone0/temp
    unit_of_measurement: "°C"
    value_template: '{{ value | multiply(0.001) | round(1) }}'

I also put a simple uptime command in the historic panel, to view system load and uptime.
Add following block
sensor:
  - platform: command_line
    name: Board Uptime
    command: /usr/bin/uptime

With an AWK filter on free command, I also display information about memory of the board.
Add following block to /home/homeassistant/.homeassistant/configuration.yaml
sensor:
  - platform: command_line
    name: Board Memory
    command: '/usr/bin/free -h | /usr/bin/awk -F " " ''FNR==2{print "Total: "$2" Used: "$3" Free: "$4}'' '

= 1-wire - temperature sensor =

From command line, verify that are present wl_gpio and wl_therm
root@pi:~# lsmod | grep -i w1_

w1_therm               24576  0
w1_gpio                16384  0
wire                   36864  2 w1_gpio,w1_therm
You should see temperature sensor here
root@pi:~# ls /sys/bus/w1/devices/
With more sensors, you will see multiple /sys/bus/w1/devices/28-xxxxxxxxxxxxx directories, each one having the unique serial number as the directory name.
You can select a sensor entering the directory (xxxxxxxxxxxxx is the serial number):
cd /sys/bus/w1/devices/28-xxxxxxxxxxxxx
cat w1_slave
Copy the serial numbers.
Add to configuration.yaml the entry for the 1-wire sensor and devices. The devices are indicated according their serial numbers: they can be renamed with a more useful friendly name.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


sensor:
  - platform: onewire

In the documentation it is stated that the sensors can be renamed using the "names" parameter according to the serial number, that should be "sensor.28_012032ca73c6_temperature". However in my setup it seems to not be working. So I used the customize directive to change label.
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


homeassistant:
  customize:
    sensor.28_012032ca73c6_temperature:
      friendly_name: Outside South
    sensor.28_012032cb2851_temperature:
      friendly_name: Outside North

= i2c - temperature, humidity, pressure sensor =

Install i2c programs to analyse the sensor addressing.
root@pi:~# apt-get install i2c-tools
Show i2c master adapter
root@pi:~# i2cdetect  -l

i2c-1   i2c             bcm2835 (i2c@7e804000)                  I2C adapter
List the i2c sensors detected
# i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 -- 

1 sensors detected in 0x76
So the address of my BME280 sensor is 0x76.
In Home Assistant configuration file add:
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


sensor:
  - platform: bme280
    name: Indoor
    i2c_address: 0x76
    operation_mode: 2
    time_standby: 2
    oversampling_temperature: 2
    oversampling_pressure: 4
    oversampling_humidity: 1
    filter_mode: 4
    delta_temperature: -1
    monitored_conditions:
      - temperature
      - humidity
      - pressure

The BME280 sensor usually is self heating himself and gives higher temperature from the true. The "delta_temperature" parameter can be set to adjust constant error in temperature measuring.
Using the two 1-wire themometer plus an external analog one, I considered that around 25 degree it has an approximate error of 1 degrees. So I correct removing 1 degrees. When doing this calibration, made adjustement after enough time the sensor was powered on.

I set the oversampling, IIR filter and standby time settings to values that in some testing done seems to give me stable readings.

= SPI SETUP =

Check that the spi_bcm2835 and spidev modules are loaded. If not, use modprobe spi_bcm2835 spidev
root@pi:~# lsmod | grep spi_bcm2835
spi_bcm2835            24576  0

root@pi:~# lsmod |grep spidev
spidev                 20480  0
You should then have some devices ready
root@pi:~# ls  -l  /dev/spi*
crw-rw---- 1 root spi 153, 0 Jan 10 12:31 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Jan 10 12:31 /dev/spidev0.1
To check if GPIO and wires are correctly wired, you can use this tool, after putting a wire between the MISO pin 19 and MOSI pin 21.
The result is some hex values as shown.
root@pi:~# wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-3.10.y/Documentation/spi/spidev_test.c
root@pi:~# gcc -o spidev_test spidev_test.c
root@pi:~# ./spidev_test -D /dev/spidev0.0
spi mode: 4
bits per word: 8
max speed: 500000 Hz (500 KHz)

FF FF FF FF FF FF 
40 00 00 00 00 95 
FF FF FF FF FF FF 
FF FF FF FF FF FF 
FF FF FF FF FF FF 
DE AD BE EF BA AD 
F0 0D 
Install Python spidev library
root@pi:~# pip3 install spidev
Give user homeassistant permission to use SPI device:
root@pi:~# usermod -a -G spi homeassistant

= SPI Channel 0 - Water Pressure =

Create the following Python script to get values from the MCP3008 channel 0. It is an instant reading of the pressure value.
You have to check the minimum voltage of the sensor at 0 Mpa with a voltmeter on the terminal block and set it to variable VMIN.
The PMAX can be set to 0.5 to use the Mpa unit, or 5 to use the Bar unit.
root@pi:~# vi /home/homeassistant/spi_mcp3008_wp.sh


#!/usr/bin/python3
# Raspberri Pi - Water Pressure reading with MCP3008 over SPI
# pip3 install spidev
# http://richiardone.eu

from spidev import SpiDev

# minimum voltage measured on sensor data
VMIN = 0.490
# maximum voltage as declared
VMAX = 4.5
# maximum pressure as declared, can be set to 0.5 for MPa or 5 for Bar
# PMAX = 0.5 # MPa
PMAX = 5 # Bar
# MCP3008 channel
CHANNEL = 0
# VRef of MCP3008
VREF = 3.3
# voltage divider ratio
VDIV = 2/3


class MCP3008:
  def __init__(self, bus = 0, device = 0):
    self.bus, self.device = bus, device
    self.spi = SpiDev()
    self.open()
        
  def open(self):
    self.spi.open(self.bus, self.device)
    self.spi.max_speed_hz = 1000000
        
  def read(self, channel = 0):
    adc = self.spi.xfer2([1, (8 + channel) << 4, 0])
    data = ((adc[1] & 3) << 8) + adc[2]
    return data
               
  def close(self):
    self.spi.close()

try:
  mcp = MCP3008()
  realv = (mcp.read(CHANNEL) * VREF / (VDIV)) / 1024
  mcp.close()
  realv = (realv - VMIN) * PMAX / (VMAX - VMIN)
  if realv < 0:
    print(0.000)
  else:
    print(round(realv, 3))
except:
  print('E')

Set correct permissions to the file
root@pi:~# chmod +x /home/homeassistant/spi_mcp3008_wp.sh
root@pi:~# chown homeassistant:homeassistant /home/homeassistant/spi_mcp3008_wp.sh
Add in configuration.yaml file:
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


sensor:
  - platform: command_line
    name: Water Pressure
    command: /home/homeassistant/spi_mcp3008_wp.sh
    unit_of_measurement: "Bar"
    scan_interval: 60

= Channel 1, 2 - AC power consumption =

Also here I am using a Python script. It waits some time to read the consumption from the sine wave peak value.

The AC sensor gives a sine waves of the frequency of the line with the amplitude corresponding to the load: I need to get the maximum and the minimum of the wave. I can also calculate the wave period. Considering a frequency of 50Hz, for Nyquist we are needing a sampling of at least 100 sample per second, that is one each 10 ms. But I wanted to be more accurate to don't miss the peak, so I wanted to use a sample each 1 ms, that as explained before with digital counter is also a interval well managed in Python over Linux kernel.

With SCT013-030 consumption of 30A (around 6.6 kW at 220VAC) corresponds to 1V RMS, that is -1.42V to +1.42V
Using 3.3V voltage divider at +1.65V, so that the measured sine wave will go from +0.23V to +3.07V
Scale is linear, so ideally VMAX goes from +1.65V to +3.07V
Formula to get W from voltage is: (VMAX - (VREF/2)) * 30 * VOLTAGE / 1.42

VREF_2 can be adjusted manually to reflect value read without any load (for example in my case I read 1.66 V
root@pi:~# vi /home/homeassistant/spi_mcp3008_ac.sh


#!/usr/bin/python3
# Raspberri Pi - AC power consumption reading with MCP3008 over SPI
# pip3 install spidev schedule
# http://richiardone.eu

from spidev import SpiDev
import asyncio
import sys
import time

# MCP3008 channel
CHANNEL = int(sys.argv[1])
# VRef on MCP3008
VREF = 3.3
VREF = 3.3
VREF_2 = VREF/2
# adjusted because without load always reading 1.66
VREF_2 = 1.66

# Current scale
MAXCURR = 30
# AC Voltage
VOLTS = 220
# 1 ms interval
SAMPLE_INT = 0.001

# wait for 20 ms to get vmax
WAIT_INTERVAL_MS = 0.02
FILE_OUT_INSTANT = '/tmp/ac{}.instant'.format(CHANNEL)


class MCP3008:
  def __init__(self, bus = 0, device = 0):
    self.bus, self.device = bus, device
    self.spi = SpiDev()
    self.open()

  def open(self):
    self.spi.open(self.bus, self.device)
    self.spi.max_speed_hz = 1000000

  def read(self, channel = 0):
    adc = self.spi.xfer2([1, (8 + channel) << 4, 0])

    data = ((adc[1] & 3) << 8) + adc[2]
    return data

  def close(self):
    self.spi.close()


async def check_ac_task(mychan):
  global mcp, vmax, flag

  vmax = VREF_2
  vmin = VREF_2
  vprec0 = VREF_2
  vprec1 = VREF_2
  vprec2 = VREF_2

  while flag:
    realv = (int(mcp.read(mychan)) * VREF / 1024)

    # I'm going down, update the vprec
    if(realv < vprec0):
      vprec0 = realv
    if(realv < vprec1):
      vprec1 = realv
    if(realv < vprec2):
      vprec2 = realv

    # then update the vmax
    if(realv > vmax):
      vmax = realv

    await asyncio.sleep(SAMPLE_INT)
  loop.stop()

async def run_for_interval(loop, task):
  global flag
  await asyncio.sleep(WAIT_INTERVAL_MS)
  flag = False


if __name__ == '__main__':
  try:
    vmax = 0
    flag = True
    mcp = MCP3008()

    loop = asyncio.get_event_loop()
    task = loop.create_task(check_ac_task(CHANNEL))
    loop.create_task(run_for_interval(loop, task))
    loop.run_forever()
    loop.close()
    mcp.close()

    # 30A (= 6.6 kW at 220VAC) corresponds to 1V RMS, that is -1.42V to +1.42V
    # using 3.3V voltage divider at +1.65V, so that the measured sine wave will go from +0.23V to +3.07V
    # scale is linear, so ideally VMAX goes from +1.65V to +3.07V
    # formula to get W from voltage is: (vmax - (VREF/2)) * MAXCURR * VOLTS / 1.42

    # prints W
    print(round(((vmax - (VREF_2)) * MAXCURR * VOLTS / 1.42), 3))

  except:
    mcp.close()
    print('E')

Set permissions to the file
root@pi:~# chmod +x /home/homeassistant/spi_mcp3008_ac.sh
root@pi:~# chown homeassistant:homeassistant /home/homeassistant/spi_mcp3008_ac.sh
Add in configuration.yaml file:
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


sensor:
  - platform: command_line
    name: AC probe 1 current consumption
    command: /home/homeassistant/spi_mcp3008_ac.sh 1
    unit_of_measurement: "W"
    scan_interval: 10

  - platform: command_line
    name: AC probe 2 current consumption
    command: /home/homeassistant/spi_mcp3008_ac.sh 2
    unit_of_measurement: "W"
    scan_interval: 10

== SOME AUTOMATIONS ==

= Climate Thermostat =

Home assistant includes automation mechanism. A simple one is a climate thermostat platform to regulate boiler activation according to indoor temperature.
Add the following to the Home Assistant configuration file
root@pi:~# vi /home/homeassistant/.homeassistant/configuration.yaml


climate:
  - platform: generic_thermostat
    name: Main Thermostat
    heater: switch.DO1_Boiler
    target_sensor: sensor.indoor_temperature
    min_temp: 10
    max_temp: 30
    target_temp: 22
    away_temp: 10
    ac_mode: false
    initial_hvac_mode: "heat"

= Outdoor lights on at night

User Automation from web interface. I created two automations: first one to light on, second one to light off. Fill the following fields:

Name -> "Turn on the lights when the sun is set"
Mode -> Single
Trigger type -> Sun
Event -> Sunset
Offset -> -00:30
Action type -> Call service
Service -> switch.turn_on
Name of entities -> switch.do3_gate_lights
Click Save

The second automation to turn the lights off:

Name -> "Turn off the lights when the sun is rising"
Mode -> Single
Trigger type -> Sun
Event -> Sunrise
Action type -> Call service
Service -> switch.turn_off
Name of entities -> switch.do3_gate_lights
Click Save

== FINAL RESULT ==

screen 3 screen 4
screen 6 wall

Here you can download complete configuration.yaml file for Home Assistant.

== MEMORY AND SPACE ANALYSIS ==

The RAM memory used on Raspberry Pi is no more that 300 MB, so the version with 2 GB is enough to run this solution, also considering the space allocated for memory filesystems (i.e. /tmp).

== IMPROVEMENTS AND FUTURE WORKS ==

The device as-is can be rated with IP20 protection. With some improvement on the side holes, adding a fine grating, and adding a custom gasket on the display, could arrive to IP42.
This is a base for many other deployment, for example some ideas:
  • Implement some history statistic in the history panel about how much time o volumes has been used. https://www.home-assistant.io/integrations/history_stats
  • Automatically alerts according to some events, for example water pressure is low since too many hours.
  • Add a speater to the Raspberry Pi and make some audio notification, from simple "cuckoo clock" at each hour to voice notification on events.
  • Use wireless connection to manage smart home commercial devices.

=== REFERENCES ===

Can't be able to build the solution without these helps, presented here in no particular order:

https://www.home-assistant.io/getting-started/automation/
https://www.home-assistant.io/integrations/onewire/
https://www.home-assistant.io/integrations/rpi_gpio/
https://www.home-assistant.io/docs/installation/raspberry-pi/
https://rc.home-assistant.io/docs/authentication/providers/#skip-login-page-examples
https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
https://www.home-assistant.io/integrations/bme280/
https://www.home-assistant.io/integrations/sensor.command_line
https://developers.home-assistant.io/docs/creating_integration_file_structure/
https://github.com/home-assistant/example-custom-config/tree/master/custom_components
https://www.raspberrypi.org/documentation/hardware/display/troubleshooting.md
https://www.raspberrypi.org/forums/viewtopic.php?t=122020
https://www.raspberrypi.org/forums/viewtopic.php?t=167896
https://raspberrypi.stackexchange.com/questions/41234/max-length-of-wire-w-3-3v-or-other-issue
https://www.raspberrypi-spy.co.uk/2020/11/raspberry-pi-temperature-monitoring/
https://electronics.stackexchange.com/questions/505318/how-to-properly-use-a-relay-module-with-jd-vcc-from-arduino-raspberry
https://www.raspberrypi.org/forums/viewtopic.php?t=118230
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/ds18b20
http://nagashur.com/blog/2017/06/25/bme280-sur-raspberry-pi-temperature-pression-et-humidite-en-i2c/
https://github.com/kbrownlees/bme280
https://pypi.org/project/enerpi/
https://www.hackster.io/ShawnHymel/hack-your-home-part-3-power-monitor-16a313
https://www.rototron.info/raspberry-pi-analog-water-sensor-tutorial/
https://www.element14.com/community/community/raspberry-pi/raspberrypi_projects/blog/2018/04/26/remote-home-monitoring-with-raspberry-pi-and-hologram-nova
https://www.maximintegrated.com/en/app-notes/index.mvp/id/148/CMP/ELK5
https://www.poweruc.pl/blogs/news/non-invasive-sensor-yhdc-sct013-000-ct-used-with-arduino-sct-013
https://maker-tutorials.com/en/auto-start-midori-browser-in-fullscreen-kiosk-modus-raspberry-pi-linux/
https://www.socsci.ru.nl/wilberth/computer/sleepAccuracy.html
https://pypi.org/project/mcp3008/
https://github.com/luxedo/RPi_mcp3008
https://pypi.org/project/spidev/
https://www.raspberryme.com/mcp3008-lecture-des-signaux-analogiques-sur-le-raspberry-pi/

phperr 0.7Sat, 13 Feb 10
Current version of my CMS phperr 0.7 is available. Added web2.0 sharing, multipage as usual without using any database, and RSS fixes. Available upon conditions of GPL v2 license.
Really simple Javascript RSS parserThu, 16 Jul 09
I was looking for a javascript parser, that works without frills and was simple. Not finding it, I write a few lines reported below:
var title = 0;
var lines = 0;

function parselevel(level, skiptext, maxlines){
  if(level.textContent.search(skiptext)==-1){
    
    if(level.nodeName == "title"){
      title = '<b>' + level.textContent + '</b><br/>';
    }

    if(level.nodeName == "description"){
      if(title != 0){
        if(maxlines == lines){
          return;
        }
        document.write('<a ');
        if(lines%2){
          document.write('style="background-color: #90e090;"');
        }
        document.write('>' + title + '' + level.textContent + '</i></a>');
        document.write('<br />');
	title = 0;
        lines = lines + 1;
      }
    }
  }

  for(var i=0; i < level.childNodes.length; i++){
    parselevel(level.childNodes[i], skiptext, maxlines);
  }
}

function parserss(rssfile, skiptext, maxlines){
  var xmlDoc=document.implementation.createDocument("","",null);

  xmlDoc.async=false;
  xmlDoc.load(rssfile);
  var root = xmlDoc.documentElement;

  title = 0;
  lines = 0;

  parselevel(root, skiptext, maxlines);
}
You call it from html page with:
<script src="rss.js" type="text/javascript"></script>
<script language="javascript"><!--
window.onload=parserss("YOURRSS.XML", /TITLE_TO_SKIP/, 5)
//--></script>
Change YOURRSS.XML with the name of rss file (it must be a local file for Gecko browsers, I download it locally with cron and fetch), TITLE_TO_SKIP is a string that exclude some RSS field to be printed, and the last is the number of RSS field to print.
phperr 0.6Sun, 18 Jan 09
New version of this simple CMS, phperr 0.6, is available. Fixed minor graphical details and added RSS capability. As usual, available upon conditions of GPL v2 license.
Random picture from PicasaSat, 9 Aug 08
Here I report the simple php code:

$userid = 'errimg'; // set your userid of picasa
$thumbsize = '108'; // set resolution of thumbnail among 54, 108 or 216

function startElement($parser, $name, $attrs){
    global $record;
    global $canstart;
    
    if($name == 'TITLE' && $attrs["TYPE"] == 'text' && $canstart)
        $record = true;
    if($name == 'ENTRY')
        $canstart = true;
}
function endElement($parser, $name){
    global $tmparray;
    global $record;
    global $curfield;
    global $canstart;

    $record = false;
    if($name == 'TITLE' && $canstart){
        $tmparray[] = $curfield;
        $curfield = '';
    }
}
function elementContent($parser, $data){
    global $curfield;
    global $record;

    if($record)
         $curfield .= $data;
}
function startIdElement($parser, $name, $attrs){
    global $canstart;
    global $tmparray;
    global $thumbsize;

    if($name == 'MEDIA:THUMBNAIL' && $attrs['HEIGHT'] == '108' && $canstart)
        $tmparray[] = $attrs['URL'];
    if($name == 'ENTRY')
        $canstart = true;
}
function endIdElement($parser, $name){
}

function getAlbums($userId){
    global $tmparray;
    global $canstart;

    $tmparray = array();
    $canstart = false;

    $url = 'http://picasaweb.google.com/data/feed/api/user/'.urlencode($userId).'?kind=album';
    $xml = file_get_contents($url);

    $xml_parser = xml_parser_create();
    xml_set_element_handler($xml_parser, "startElement", "endElement");
    xml_set_character_data_handler($xml_parser, 'elementContent');
    xml_parse($xml_parser, $xml);
    xml_parser_free($xml_parser);
}

function showAlbumContent($userId, $albumName){
    global $tmparray;
    global $canstart;

    $tmparray = array();
    $canstart = false;

    $url = 'http://picasaweb.google.com/data/feed/api/user/'.urlencode($userId).'/album/'.urlencode($albumName);
    $xml = file_get_contents($url);
    
    $xml_parser = xml_parser_create();
    xml_set_element_handler($xml_parser, "startIdElement", "endIdElement");
    xml_parse($xml_parser, $xml);
    xml_parser_free($xml_parser);
}

getAlbums($userid);

if(!empty($tmparray)){
  $album_title = $tmparray[array_rand($tmparray, 1)];
  $album_title = ereg_replace("[^A-Za-z0-9]", "", $album_title);
  showAlbumContent($userid, $album_title);
  if(!empty($tmparray)){
     $random_pic = $tmparray[array_rand($tmparray, 1)];
     print '<a href="http://picasaweb.google.com/'.$userid.'/'.$album_title
        .'"><img src="'.$random_pic .'" alt=""></a>';
  }
}

phperrDec 2007
I forgot to link here the humble CMS running this site, called with fantasy phperr.
You can get it here (version 0.5); keep in mind that is very my-site oriented, but the code lines are few and it can be easily more developed.
Contents are stored in text files (no database required) and are edited in html stile blog; it support upload and management of remote files. The number of pages are unlimited and created as you access them (in wiki stile). Border menus are are also remotely editable in php.
WaNDA-toolsDec 2007
The WaNDA Project has reached a stable status. It allows you to generate a multiplatform offline version of Wikipedia. More info are available at the project page on Sourceforge, where you can get it.

There's also a page at Politechnic of Turin, linux@studenti, and my MSc thesis in italian about it, here available in texts section.

The code is a mix of PHP for processing and multiplatform ECMAscript for consulting the offline content.
ErmesJun 2006
"Ermes" is a Windows multicast network application for video conferencing; using video compressions techniques, it streams a desktop area from a server machine to unlimited numbers of clients.

The communication is done with two streams: the audio stream has priority over video, so position of mouse cursor is included with it for improved clearness of speech. The video stream compression is settable to suit situation needs. The programs should run on all Windows NT family (XP, etc..). It works in either client or server mode.
Full sources for Visual Studio 2005 (.NET) are released under GPL v2; the software is mainly written in C# with managed C++.

Sources: Ermes_v0.4.5.zip
Brief documentation in italian with schemes of components: Ermes.pdf
zenzeroJan 2005
"zenzero" e` il nome in codice di un breve progetto per il controllo di un autoveicolo.
Il veicolo e` costruito con Lego Mindstorms, il software di controllo e` basata su Statetra e LegoStatetra.

La documentazione del progetto: zenzero.pdf
Il sorgente Statetra del sofware di gestione: zenzero_str.tar.bz2
8051 MicrocontrollerAug 2004
Microcontrollore 8051: un testo in italiano che contiene sia un'esaustiva descrizione dell'architettura che una guida alla programmazione in assembler su processori embedded di questo tipo.
La piattaforma di sviluppo di riferimento e` il Keil A51, l'integrato ed i compenenti annessi e` della Phytec.

Il testo e` presente qui Microcontrollore_8051.pdf
Gli esempi inclusi nel testo sono disponibili qui 8051_code_examples.zip

Il progetto e` stato sviluppato per la laurea di primo livello in collaborazione con fosk.
hchlib16 Mar 04
Http CHannel LIBrary: an useless generic HTTP network layer.
It permits point to point communication using HTTP and MIME, encoding data with Quoted Printable or Base64.

From the SF page:
Http_channel_lib is a UNIX library to establish a client/server communication trought HTTP/1.0 and MIME. It can encode data (base64, quoted printable) and it's compliant with RFCs 821, 1945, 2045. Included full documentation in italian.

The library sources are also available here: hchlib_1.0.tar.gz
In the package is included as documentation the list of API and slides on how-it-works, both in italian: HTTP_adaptation_layer_API.pdf HTTP_adaptation_layer_SLIDES.pdf

The project was developped with fosk.

top   multi page
apache php i prefer firefox W3C html 4.0 compliant W3C css compliant
W3Counter
This website uses only essential technical cookies.
Emmanuel Roberto Richiardone (e AT richiardone DOT eu)

All contents, where applicable and except otherwise specified, are present under GPLv2 or GFDL licenses.
E. Richiardone (e AT richiardone DOT eu)

page viewed 30804 times and generated in 0.008417 s