The Central Access Point is running on a Raspberry Pi Zero W
$ sudo apt update
$ sudo apt full-upgrade
# dnsmasq - This program has extensive features, but for our purposes we are using it as a DHCP server for our WiFi AP.
# hostapd - This program defines our AP’s physical operation based on driver configuration.
$ sudo apt-get install dnsmasq hostapd
Install grafana Ubuntu and Debian(ARMv6): https://grafana.com/grafana/download/9.3.6?edition=enterprise&platform=arm
sudo apt-get install -y adduser libfontconfig1 musl
wget https://dl.grafana.com/enterprise/release/grafana-enterprise-rpi_9.3.6_armhf.deb
sudo dpkg -i grafana-enterprise-rpi_9.3.6_armhf.deb
Config file: /etc/grafana/grafana.ini
Install sqlite plugin
grafana-cli plugins install frser-sqlite-datasource
Enable and Start grafana
sudo /bin/systemctl enable grafana-server
sudo /bin/systemctl start grafana-server
-
Check the existing network
This is what you can see before configuringpi@raspberrypi:~$ iw dev phy#0 Unnamed/non-netdev interface wdev 0x4 addr ba:27:eb:07:28:1f type P2P-device txpower 31.00 dBm Interface wlan0 ifindex 2 wdev 0x1 addr b8:27:eb:ff:ff:ff ssid <YOUR HOME SSID> type managed channel 1 (2437 MHz), width: 20 MHz, center1: 2437 MHz txpower 31.00 dBm
-
Configure dnsmasq
Let’s call our new interface for AP to uap0 Here we can define the IP interval what we use for the nodes connecting to this AP. In this case it will be between 192.168.50.50 and 192.168.50.150pi@raspberrypi:~$ /etc/dnsmasq.conf interface=lo,uap0 no-dhcp-interface=lo,wlan0 bind-interfaces server=8.8.8.8 domain-needed bogus-priv dhcp-range=192.168.50.50,192.168.50.150,24h
-
Configure hostapd
Here the channel is hardcoded. There is a dynamic and better way to find out the right channel. I’ll show it laterpi@raspberrypi:~$ vi /etc/hostapd/hostapd.conf interface=uap0 ssid=Central-Station-006 hw_mode=g channel=1 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_passphrase=viragfal wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP
-
Configure wifi network interface file
pi@raspberrypi:~$ vi /etc/wpa_supplicant/wpa_supplicant.conf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="****" psk="****" key_mgmt=WPA-PSK id_str="AP1" } network={ ssid="****" psk="****" key_mgmt=WPA-PSK id_str="AP2" }
-
Configure AP interface file
pi@raspberrypi:~$ vi /etc/network/interfaces source-directory /etc/network/interfaces.d auto lo auto uap0 auto wlan0 iface lo inet loopback allow-hotplug uap0 iface uap0 inet static address 192.168.50.3 netmask 255.255.255.0 hostapd /etc/hostapd/hostapd.conf allow-hotplug wlan0 iface wlan0 inet manual wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf iface AP1 inet dhcp iface AP2 inet dhcp
-
Script to put all together
pi@raspberrypi:~$ /usr/local/bin/hostapdstart.sh #!/bin/bash mac=`sudo ifconfig |grep ether | sed 's/ether \([a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]\).*/\1/g' | head -n 1` sudo /sbin/iw phy phy0 interface add uap0 type __ap sudo /bin/ip link set uap0 address $mac sudo ifdown --force wlan0 sudo ifdown --force uap0 sudo ifup uap0 sudo ifup wlan0 # Fetch wifi channel CHANNEL=`iwlist wlan0 channel | grep Current | sed 's/.*Channel \([0-9]*\).*/\1/g'` export CHANNEL # Create the config for hostapd #cat /etc/hostapd/hostapd.conf.tmpl | envsubst > /etc/hostapd/hostapd.conf # Uncomment the two following lines to get access to internet #sysctl net.ipv4.ip_forward=1 #iptables -t nat -A POSTROUTING -s 192.168.50.0/24 ! -d 192.168.50.0/24 -j MASQUERADE sudo systemctl restart hostapd sleep 10 sudo systemctl restart dnsmasq sleep 10 sudo systemctl restart dhcpcd
-
unmask hostapd
pi@raspberrypi:~$ sudo systemctl unmask hostapd pi@raspberrypi:~$ sudo systemctl enable hostapd pi@raspberrypi:~$ sudo systemctl start hostapd
-
Run the script just after the reboot automatically
In the crontab file:root@raspberrypi:~$ crontab -e @reboot /usr/local/bin/hostapdstart.sh
-
Check the existing network after the configuration
You can see the new Interface: uap0root@raspberrypi:~# iw dev phy#0 Unnamed/non-netdev interface wdev 0x3 addr ba:27:eb:97:d5:fe type P2P-device txpower 31.00 dBm Interface uap0 ifindex 3 wdev 0x2 addr b8:27:eb:97:d5:fe ssid Central-Station-006 type AP channel 1 (2412 MHz), width: 20 MHz, center1: 2412 MHz txpower 31.00 dBm Interface wlan0 ifindex 2 wdev 0x1 addr b8:27:eb:ff:ff:ff ssid <YOUR HOME SSID> type managed channel 1 (2437 MHz), width: 20 MHz, center1: 2437 MHz txpower 31.00 dBm
root@raspberrypi:~# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether b8:27:eb:97:d5:fe brd ff:ff:ff:ff:ff:ff inet 192.168.0.103/24 brd 192.168.0.255 scope global dynamic wlan0 valid_lft 1966sec preferred_lft 1966sec inet6 fdaa:bbcc:ddee:0:ba27:ebff:fe97:d5fe/64 scope global dynamic mngtmpaddr valid_lft 2006054648sec preferred_lft 2006054648sec inet6 fe80::ba27:ebff:fe97:d5fe/64 scope link valid_lft forever preferred_lft forever 3: uap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether b8:27:eb:97:d5:fe brd ff:ff:ff:ff:ff:ff inet 192.168.50.3/24 brd 192.168.50.255 scope global uap0 valid_lft forever preferred_lft forever inet6 fe80::ba27:ebff:fe97:d5fe/64 scope link valid_lft forever preferred_lft forever
graph LR
/var/spool/cron/crontabs/root --> /home/pi/Projects/diy-greenwall/Software/Central.AccessPoint-RaspberryPi/python/start
/var/spool/cron/crontabs/root --> /usr/local/bin/hostapdstart.sh
/usr/local/bin/hostapdstart.sh --> /etc/dnsmasq.conf
/usr/local/bin/hostapdstart.sh --> /etc/network/interfaces
/etc/network/interfaces --> /etc/hostapd/hostapd.conf
/etc/network/interfaces --> /etc/wpa_supplicant/wpa_supplicant.conf
pi@raspberrypi:~ $ sudo apt install python3-venv
pi@raspberrypi:~ $ cd /var/www/greenwall/python
pi@raspberrypi:/var/www/greenwall/python $ python3 -m venv env
pi@raspberrypi:~ $ sudo apt-get install iptables-persistent
pi@raspberrypi:~ $ sudo apt-get install libapache2-mod-wsgi-py3
pi@raspberrypi:/var/www/greenwall/python $ source env/bin/activate
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip install requests
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install python-dateutil
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ python -m pip install flask
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip install Flask-Classful==0.15.0b1
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install -U flask-cors
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install rpi_lcd
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install evdev
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install psutil
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip install scipy --no-cache-dir
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip install matplotlib
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install pandas
(env) pi@raspberrypi:/var/www/greenwall/python/env/bin $ pip3 install natsort
$ sudo apt-get install python3-sklearn python3-sklearn-lib
$ pip3 install opencv-python
First you should clone the diy-greenwall project from the GitHub.
$ cd
$ mkdir Projects
$ git clone https://github.com/dallaszkorben/diy-greenwall.git
As you need only the hierarcy under the diy-greenwall/Software/Central.AccessPoint-RaspberryPi folder, on the Rasberry Pi, you can filter out the not necesary parts. But it is not mandatory to do
$ cd diy-greenwall
$ git filter-branch -f --subdirectory-filter Software/Central.AccessPoint-RaspberryPi
Under the python folder, you can see the following hierarchy of the python code:
.
├── config
│ ├── config.py
│ ├── ini_location.py
│ ├── __init.py__
│ ├── permanent_data.py
│ ├── property.py
│ └── __pycache__
│ ├── config.cpython-37.pyc
│ ├── ini_location.cpython-37.pyc
│ ├── permanent_data.cpython-37.pyc
│ └── property.cpython-37.pyc
├── controlbox
│ ├── controlbox.py
│ ├── __init__.py
│ └── __pycache__
│ ├── controlbox.cpython-37.pyc
│ └── __init__.cpython-37.pyc
├── exceptions
│ ├── __init.py__
│ ├── invalid_api_usage.py
│ └── __pycache__
│ └── invalid_api_usage.cpython-37.pyc
├── graph
│ ├── graph_level.py
│ ├── __init.py__
│ └── __pycache__
│ └── graph_level.cpython-37.pyc
├── greenwall.wsgi
├── ky040
│ ├── __init__.py
│ ├── ky040.py
│ └── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── ky040.cpython-37.pyc
│ └── KY040.cpython-37.pyc
├── restserver
│ ├── endpoints
│ │ ├── ep_info_functions.py
│ │ ├── ep_info_graph.py
│ │ ├── ep_info_timestamp.py
│ │ ├── ep_level_add.py
│ │ ├── ep.py
│ │ ├── __init.py__
│ │ ├── __pycache__
│ │ │ ├── ep.cpython-37.pyc
│ │ │ ├── ep_info_functions.cpython-37.pyc
│ │ │ ├── ep_info_graph.cpython-37.pyc
│ │ │ ├── ep_info_level.cpython-37.pyc
│ │ │ ├── ep_info_timestamp.cpython-37.pyc
│ │ │ ├── ep_info_trend.cpython-37.pyc
│ │ │ ├── ep_level_add.cpython-37.pyc
│ │ │ └── ep_level_read.cpython-37.pyc
│ │ ├── representations.py
│ │ └── ~toDelete
│ │ └── ep_info_level.py
│ ├── gradual_thread_controller.py
│ ├── __init.py__
│ ├── __pycache__
│ │ ├── gradual_thread_controller.cpython-37.pyc
│ │ ├── representations.cpython-37.pyc
│ │ ├── view_info.cpython-37.pyc
│ │ ├── view_level.cpython-37.pyc
│ │ └── ws_greenwall.cpython-37.pyc
│ ├── representations.py
│ ├── view_info.py
│ ├── view_level.py
│ └── ws_greenwall.py
├── start.py
└── utilities
├── __init.py__
├── __pycache__
│ └── report.cpython-37.pyc
└── report.py
Apache2 server should be installed and configured to allow browsers to connect and see the statuses of Sensors
-
Find the codes under web-location/greenwall/ folder
. └── greenwall ├── favicon.ico ├── /graph-images ├── /index.html └── /script ├── /jquery │ └── jquery-3.6.0.min.js └── /jquery-ui ├── AUTHORS.txt ├── /external │ └── /jquery │ └── jquery.js ├── images ├── index.html ├── jquery-ui.css ├── jquery-ui.js ├── jquery-ui.min.css ├── jquery-ui.min.js ├── jquery-ui.structure.css ├── jquery-ui.structure.min.css ├── jquery-ui.theme.css ├── jquery-ui.theme.min.css ├── LICENSE.txt └── package.json
-
Copy the the whole folder to /var/www folder
pi@raspberrypi:~$ cd web-location pi@raspberrypi:web-location$ cp -r greenwall /var/www/
-
Configure available Apach2 config file
Alternativaly you can copy the green-wall.conf file, found under the web-config folder to the /etc/apache2/conf-available folder on the Raspberry pipi@raspberrypi:~$ touch /etc/apache2/conf-available/green-wall.conf WSGIRestrictStdout Off WSGIApplicationGroup %{GLOBAL} <VirtualHost *:80> ServerAdmin [email protected] ServerName www.greenwallsite.com ServerAlias greenwallsite.com ErrorLog /var/www/greenwall/logs/error.log CustomLog /var/www/greenwall/logs/access.log combined WSGIDaemonProcess greenwall user=pi group=pi threads=5 python-home=/var/www/greenwall/python/env WSGIProcessGroup greenwall WSGIScriptAlias / /var/www/greenwall/python/greenwall.wsgi <IfModule dir_module> DirectoryIndex index.html </IfModule> Alias /greenwall/ /var/www/greenwall/ <Directory /var/www/greenwall> Order allow,deny Allow from all </Directory> </VirtualHost>
-
Configure enabled Apach2 config file
pi@raspberrypi:~$ ln -s /etc/apache2/conf-available/green-wall.conf /etc/apache2/conf-enabled/green-wall.conf
-
Install mod_wsgi
pi@raspberrypi:~$ sudo apt-get install libapache2-mod-wsgi python-dev
-
Enable mod_wsgi
pi@raspberrypi:~$ sudo a2enmod wsgi
-
Restart Apach2 service
~~pi@raspberrypi:~$ sudo /etc/init.d/apache2 restart~~ pi@raspberrypi:~$ sudo systemctl restart apache2
sequenceDiagram
participant Cam
participant PI
participant WEB browser
loop CamRegister
Cam->>PI: POST /cam/register
PI->>PI: register
end
loop AutomaticSaveFrame
Cam->>PI: POST /cam/save/frame/camId/<camId>
PI->>PI: save file
end
loop GetRegisteredCams
WEB browser->>PI: GET /cam/captureList
PI->>WEB browser: gives back the registered cams
end
loop SaveCaptureByRequest
WEB browser->>PI: GET /cam/capture/url
PI->>Cam: GET /capture
Cam->>Cam: take photo
Cam->>PI: send back photo
PI->>WEB browser: gives back the url to the photo
end
loop GenerateVideoFromFrames
WEB browser->>PI: POST /cam/construct/video {camId,startDate,endDate,fps}
PI->>PI: construct the video in the background
end
Why do we need it? Because in development/test phase I use the stand alone WSGI server to receive REST requests from the Sensor Stations and Control Stations. The stand alone WSGI server uses port 5000.
But later, I use the integrated WSGI in the Apache server, instead of the stand alone WSGI. That means, the port changes to 80. But I do not want to change the code all the time in the Station modules, when I change the WSGI. To make it work in both case I have to do a port forwarding. If the Central Controler Unit receive a rest request to port 5000, it should be mapped to port 80 instead.
root@raspberrypi:~# echo "1" /proc/sys/net/ipv4/ip_forward
root@raspberrypi:~# iptables -t nat -A PREROUTING -p tcp -d 192.168.50.3 --dport 5000 -j DNAT --to-destination 192.168.50.3:80
root@raspberrypi:~# iptables -t nat -A POSTROUTING -j MASQUERADE
The firewall should look like this:
root@raspberrypi:~# iptables -t nat -L --line-numbers
Chain PREROUTING (policy ACCEPT)
num target prot opt source destination
1 DNAT tcp -- anywhere 192.168.50.3 tcp dpt:5000 to:192.168.50.3:80
Chain INPUT (policy ACCEPT)
num target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
num target prot opt source destination
1 MASQUERADE all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
Unfortunatelly this settings will disappear after a reset, so you have to make it persistent.
root@raspberrypi:~# /sbin/iptables-save > /etc/iptables/rules.v4
root@raspberrypi:~# cat /etc/iptables/rules.v4
# iptables-persisten was already installed
# make sure the service is enabled
root@raspberrypi:~# sudo systemctl is-enabled netfilter-persistent.service
enabled
# if it is not, then enable it
root@raspberrypi:~# sudo systemctl enable netfilter-persistent.service
# get status
sudo systemctl status netfilter-persistent.service
To enable/configure the rotary-encoder device tree overlay, simply put something like the following into /boot/config.txt (with the encoder connected to pins 5 and 6 on the Raspberry Pi) While you’re at it, you might also want to add the middle button as a key (mine is connected to pin 13):
- enable rotary encoder
pi@raspberrypi:~$ vi /boot/config.txt dtoverlay=rotary-encoder,pin_a=5,pin_b=6,relative_axis=1 dtoverlay=gpio-key,gpio=13,keycode=28,label="ENTER"
After a reboot you’ll have a new device in /dev/input/ for the rotary encoder. You can use the evtest tool (as in evtest /dev/input/event0) to look at the events it generates and confirm that it reacts perfectly to every turn of the encoder, without missing a movement or confusing the direction.
- Here is an example, shows how to read the output of the rotary encoder.
from __future__ import print_function import evdev import select devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] devices = {dev.fd: dev for dev in devices} value = 1 print("Value: {0}".format(value)) done = False while True: r, w, x = select.select(devices, [], []) for fd in r: for event in devices[fd].read(): event = evdev.util.categorize(event) if isinstance(event, evdev.events.RelEvent): value = value + event.event.value print("Value: {0}".format(value)) elif isinstance(event, evdev.events.KeyEvent): if event.keycode == "KEY_ENTER" and event.keystate == event.key_up: print("Enter")
- In the Raspberry Pi run the "Raspberry Pi Configuration" application and undert the "Interfaces" tab, Enable the I2C
- Connect the pins of LCD display to the corresponding pins of RP
- GND -> GND
- VCC -> 5V
- SDA -> SDA1
- SCL -> SCL1
- Check th eaddress of the I2C box on the RP
pi@raspberrypi:/var/www $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Raspberry PI LCD Rotary
____________________________
pin Function
3 GPIO 2 SDA
5 GPIO 3 SCL
4 5V VCC
9 GND GND Rotary encoder
_______________
2 5V + / _ \
6 GND GND | / \ |
29 GPIO 5 CLK | |
31 GPIO 6 TD | | o | |
33 GPIO 13 SW | |
| \ / |
| - |
| C G |
Raspberry PI W Zero | L T S N |
__________________ | K D W + D |
/ | | \ | |
| | | | | o o o o o |
| ------ | \__|__|__|__|__|_/
| 1 2 | | | | | |
| o o-----------------------------------|--|--|--' |
| .-----------o o------------------------. | | | |
| | .--------o o-----------------------------------|--|--|-----'
| | | o o | | | | |
| | | .-------o o | .-----------------' | |
| | | | o o | | | | |
| | | | o o | .----------------------' |
| | | | o o | | | | |
| | | | o o | .---------------------------'
| | | | o o | | | | |
| | | | o o | | | | |
| | | | o o | | | | |
| | | | o o | | | | |
| | | | o o | | | | | LCD Display
| | | | .-----o o | | | | | ____________________
| | | | | .---o o | | | | | / S S V G \
| | | | | | .-o o | | | | | | C D C N |
| | | | | | | o o | | | | | | L A C D |
| | | | | | | o o | | | | | | |
| | | | | | | o o | | | | | | o o o o |
| | | | | | | 39 40 | | | | | | | | | | |
\|_|_|_|_|_|_______/ | | | | \______|__|__|__|____/
| | | | | | | | | | | | | |
| | | | | `------------------' | | | | | | |
| | | | `----------------------' | | | | | |
| | | `--------------------------' | | | | |
| | | | | | | |
| | | `----------|--|-' |
| | | | | |
| | `-----------------------------------------------|--|----'
| `-------------------------------------------------' |
`------------------------------------------------------'