Reinstalls of RPi's

Reinstalls of RPi's
Pi Zero W

I run multiple RPi's, a 3B and a ZeroW. They are both quite old now and haven't been upgraded to the latest OS. I've had the 3B since mid 2017 and I haven't installed a new Raspbian since I got it...

I've blown the dust off the Pi Zero W and reinstalled the latest version of debian using the Imager https://www.raspberrypi.com/software/
This was so simple and much easier than years before with the old Rasbian OS.
I installed the OS Lite as ill be running headless.

I have a few things connected to the GPIO:
- SainSmart 2-Channel 5V Relay Module (Newer versions are available now...)
- Bosch bme280 module (Digital Temperature/Humidity/Barometric Pressure)


Installation

After updating the distro with sudo apt update, apt full-upgrade.

- GaragePi - https://github.com/Responseless/GaragePi (Custom version of relay trigger for the sliding front gate)
- bme280 MQTT script (logs Temp/Humidity/Pressure to HA)
- bluepy Broodminder bluetooth MQTT script (logs Temp/Weights/Other to HA)

Prerequisites

Were using python3 so we usually would install pip3 and any other python modules your scripts use. On this version of debian on the PiZero W we dont use pip so we can install modules from apt or pip3, depending on the environment.

RPIZeroW >

sudo apt install i2c-tools
sudo apt install python3-smbus
sudo apt install python3-bme280
RPi3B >

sudo pip3 install smbus2
sudo pip3 install RPi.bme280

We're using the I2C so this can be enabled in raspi-config. Interface Options > I2C > enable.

sudo raspi-config

edit the boot config to include the line below:

sudo nano /boot/firmware/config.txt

dtoverlay=w1-gpio

-

sudo nano /etc/modules

w1-gpio
w1-therm

reboot the pi zero

sudo reboot now

Wait a minute for it to restart and connect with SSH again.

get_bme280.py - Pulls current values from the bme280 module temp,humidity, pressure.

#!/usr/bin/python3
import smbus2
import bme280

# bme280 settings
bme280_port = 1
bme280_address = 0x76
bme280_bus = smbus2.SMBus(bme280_port)

calibration_params = bme280.load_calibration_params(bme280_bus, bme280_address)

# the sample method will take a single reading and return a
# compensated_reading object
bme280_data = bme280.sample(bme280_bus, bme280_address, calibration_params)

# the compensated_reading class has the following attributes
print(bme280_data.id)
print(bme280_data.timestamp)
print(bme280_data.temperature)
print(bme280_data.pressure)
print(bme280_data.humidity)

# there is a handy string representation too
print(bme280_data)

create the file with these contents above. Output will show below.

chmod +x get_bme280.py

python3 get_bme280.py
user@pizeroW:~/bme280 $ python3 get_bme280.py
68a1955d-d268-42a4-9795-be981c2071a7
2024-05-09 11:47:50.917301+00:00
24.910461120144465
1013.6039477597245
39.39722134492959
compensated_reading(id=68a1955d-d268-42a4-9795-be981c2071a7, timestamp=2024-05-09 11:47:50.917301UTC, temp=24.910 °C, pressure=1013.60 hPa, humidity=39.40 % rH)

BM_Scan.py

This was a little trickier of an upgrade with the new debian version the bluepy library didnt exist as an apt package (python3-bluepy).

sudo pip install python-pip
sudo pip install bluepy --break-system-packages

We then need to work around this by installing pip and forcing it in. This worked fine and everything installed correctly.

BM_Scan.py – Scans using bluetooth for Broodminder devices and decodes the data.

#!/usr/bin/python3

from bluepy.btle import Scanner, DefaultDelegate
import json

def byte(str, byteNum):
    # https://stackoverflow.com/questions/5649407/hexadecimal-string-to-byte-array-in-python
    # Trapping for 'str' passed as 'None'
    if (str == None):
        return ''
    return str[byteNum * 2] + str[byteNum * 2 + 1]


def checkBM(data):
    check = False
    byteCheck = 0
    BMIFLLC = str("8d02")
    # print (byte(data,byteCheck))
    if (BMIFLLC == byte(data, byteCheck) + byte(data, byteCheck + 1)):
        print("  Found BroodMinder device")
        check = True
    return check


def extractData(deviceId, data):

    offset = 8  # There are 8 bits less than described in BroodMinder documentation
    lbtokg = 0.45359237  # lb to kg

    byteNumAdvdeviceModelIFllc_1 = 10 - offset
    byteNumAdvDeviceVersionMinor_1 = 11 - offset
    byteNumAdvDeviceVersionMajor_1 = 12 - offset
    byteNumAdvBattery_1V2 = 14 - offset
    byteNumAdvElapsed_2 = 15 - offset   # This is the sample number from the device.
    byteNumAdvElapsed_2b = 16 - offset
    byteNumAdvTemperature_2 = 17 - offset
    byteNumAdvTemperature_2b = 18 - offset
    byteNumAdvWeightL1 = 20 - offset
    byteNumAdvWeightL2 = 21 - offset
    byteNumAdvWeightR1 = 22 - offset
    byteNumAdvWeightR2 = 23 - offset
    byteNumAdvHumidity = 24 - offset
    byteNumAdvWeightL2SM_Time0 = 25 - offset
    byteNumAdvWeightL2SM_Time1 = 26 - offset
    byteNumAdvWeightR2SM_Time2 = 27 - offset
    byteNumAdvWeightR2SM_Time3 = 28 - offset
    byteNumAdvRealtimeTotalWeight_SwarmState = 29 - offset
    byteNumAdvRealtimeTotalWeight = 30 - offset

    # BM Models (as of early 2024)

    # T (41, 47)    # TH (42, 56)
    # W (43, 57)    # W3/W4 (49)
    # SubHub (52)    # Hub (54)
    # DIY (58)    # BeeDar (63)

    # Current sample number from the device.
    sampleNumber = int(byte(data, byteNumAdvElapsed_2b), 16) + int(byte(data, byteNumAdvElapsed_2), 16)

    # Model
    modelNumber = int(byte(data, byteNumAdvdeviceModelIFllc_1), 16)

    # Version
    versionNumber = str(int(byte(data, byteNumAdvDeviceVersionMajor_1), 16)) + "." + str(int(byte(data, byteNumAdvDeviceVersionMinor_1), 16))

    print("  Model Number = {}, Version = {}, Sample = {}".format(modelNumber, versionNumber, sampleNumber))

    #defaults for non weigth devices
    realTimeWeight_lb = 0
    realTimeWeight_kg = 0

#    if modelNumber == 41 or modelNumber == 42 or modelNumber == 43:
#        continue


    if modelNumber == 49 or modelNumber == 57 or modelNumber == 58:
        weightR = (int(byte(data, byteNumAdvWeightL2), 16) * 256 + int(byte(data, byteNumAdvWeightL1), 16)) - 32767
        weightScaledR_lb = float(weightR / 100)
        weightScaledR_kg = weightScaledR_lb * lbtokg
        weightL = (int(byte(data, byteNumAdvWeightR2), 16) * 256 + int(byte(data, byteNumAdvWeightR1), 16)) - 32767
        weightScaledL_lb = float(weightL / 100)
        weightScaledL_kg = weightScaledL_lb * lbtokg

        weightR2 = (int(byte(data, byteNumAdvWeightL2SM_Time1), 16) * 256 + int(byte(data, byteNumAdvWeightL2SM_Time0), 16)) - 32767
        weightScaledR2_lb = float(weightR2 / 100)
        weightScaledR2_kg = weightScaledR2_lb * lbtokg
        weightL2 = (int(byte(data, byteNumAdvWeightR2SM_Time3), 16) * 256 + int(byte(data, byteNumAdvWeightR2SM_Time2), 16)) - 32767
        weightScaledL2_lb = float(weightL2 / 100)
        weightScaledL2_kg = weightScaledL2_lb * lbtokg

    #    print("  Scale R1 kg = {}".format(weightScaledR_kg))
    #    print("  Scale R2 kg = {}".format(weightScaledR2_kg))
    #    print("  Scale L1 kg = {}".format(weightScaledL_kg))
    #    print("  Scale L2 kg = {}".format(weightScaledL2_kg))
    #    print("  Scaled Total kg = {}".format(weightScaledR_kg+weightScaledR2_kg+weightScaledL_kg+weightScaledL2_kg))

        realTimeWeight_lb = ((int(byte(data, byteNumAdvRealtimeTotalWeight), 16) * 256 + int(byte(data, byteNumAdvRealtimeTotalWeight_SwarmState), 16) - 32767 ) / 100)
        realTimeWeight_kg = round(realTimeWeight_lb * lbtokg, 2)
        realTimeWeight_lb = round(realTimeWeight_lb, 2)

    #    print("  realTimeWeight kg = {}".format(realTimeWeight_kg))

    batteryPercent = int(byte(data, byteNumAdvBattery_1V2), 16)

    # Temps
    temperatureDegreesC = int(byte(data, byteNumAdvTemperature_2b) + byte(data, byteNumAdvTemperature_2), 16)
    temperatureDegreesC = (float(temperatureDegreesC) - 5000) / 100
    temperatureDegreesF = round((temperatureDegreesC * 9 / 5) + 32, 2)
    temperatureDegreesC = round(temperatureDegreesC, 2)
    
    # Humidity (0 for 41/47/49/52)
    if modelNumber == 41 or modelNumber == 47 or modelNumber == 49 or modelNumber == 52:
        humidityPercent = 0
    else:
        humidityPercent = int(byte(data, byteNumAdvHumidity))

    #print("    Weight = {} kg {} lb, TemperatureC = {} C {} F, Humidity = {} %, Battery = {} %".format(realTimeWeight_kg, realTimeWeight_lb, temperatureDegreesC, temperatureDegreesF, humidityPercent, batteryPercent))

    data = {"sampleNumber": sampleNumber,
            "modelNumber": modelNumber,
            "versionNumber": versionNumber,
            "sampleNumber": sampleNumber,
            "batteryPercent": batteryPercent,
            "realTimeWeight_lb": realTimeWeight_lb,
            "realTimeWeight_kg": realTimeWeight_kg,
            "temperatureDegreesC": temperatureDegreesC,
            "temperatureDegreesF": temperatureDegreesF,
            "humidityPercent": humidityPercent
            }

    print (data)
    json_data = json.dumps(data)


def processData(pdev):
    if (checkBM(pdev.getValueText(255))):
        print("  Device {} ({}), RSSI={} dB".format(pdev.addr, pdev.addrType, pdev.rssi))
        for (adtype, desc, value) in pdev.getScanData():
            print("    %s = %s" % (desc, value))

            # Trap for the BroodMinder ID
            if (desc == "Complete Local Name"):
                extractData(value, pdev.getValueText(255))

            # Trap for evertyhing
            extractData(value, pdev.getValueText(255))


class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            # print("  Discovered device {}".format(dev.addr))
            processData(dev)

        elif isNewData:
            # print("  Received data from {}".format(dev.addr))
            processData(dev)

scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(30.0)

The scripts are on my github with their equivalent MQTT versions (in progress).

GIT Links: TBA


Pi Zero W - SSH Lag Issue

The issue is Wifi power saving mode. This can be disabled by adding the file:

/etc/NetworkManager/conf.d/default-wifi-powersave-on.conf 

with contents:

[connection]
wifi.powersave = 2


Details here: https://gist.github.com/jcberthon/ea8cfe278998968ba7c5a95344bc8b55