log

tech notes

Just a reminder for the next time


r := mux.NewRouter()

subrouter := r.PathPrefix("/prefix").Subrouter()

subrouter.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { 
  // ...
}).Methods("POST", "GET").Schemes("http")

I want to write test in vscode and run them by hitting F5.

  • To get this to work I had to move to the Run tab

  • Open the configuration file with the cog button

  • Add a configuration

         {
            "name": "Launch test function",
            "type": "go",
            "request": "launch",
            "mode": "test",
            "program": "${workspaceFolder}",
            "args": [
                "-test.v",
                "-test.run",
                "^TestHTTPServerGetID$",
            ],
            "showLog": false
        }
    
  • Set a breakpoint and hit F5 at will!

References:

Notes:

  • The "^TestHTTPServerGetID$", part indicates the test. It allows for a regular expression.
  • Ensure to set the subfolder eg. "program": "${workspaceFolder}/subpackge",

raspi-config

The raspi-config CLI can be used also headless with a lot of utilities for bash scripting.

This thread explain in more details.

Is a PI4 ? Run raspi-config nonint is_pifour to know

Working with Picamera

# enable picamera
sudo raspi-config nonint do_camera 1
# get picamera status
sudo raspi-config nonint get_camera

In general values are 1 to set on or 0 to off. Follow a list of possible commands

raspi-config nonint get_can_expand
raspi-config nonint do_expand_rootfs
raspi-config nonint get_hostname
raspi-config nonint do_hostname "yourhostname"
raspi-config nonint get_boot_cli
raspi-config nonint get_autologin
raspi-config nonint do_boot_behaviour B1
raspi-config nonint do_boot_behaviour B2
raspi-config nonint do_boot_behaviour B3
raspi-config nonint do_boot_behaviour B4
raspi-config nonint get_boot_wait
raspi-config nonint do_boot_wait 1|0
raspi-config nonint get_boot_splash
raspi-config nonint do_boot_splash 1|0
raspi-config nonint get_overscan
raspi-config nonint do_overscan 1|0
raspi-config nonint get_pixdub
raspi-config nonint do_pixdub 1|0
raspi-config nonint get_camera
raspi-config nonint do_camera 1|0
raspi-config nonint get_ssh
raspi-config nonint do_ssh 1|0
raspi-config nonint get_vnc
raspi-config nonint do_vnc 1|0
raspi-config nonint get_spi
raspi-config nonint do_spi 1|0
raspi-config nonint get_i2c
raspi-config nonint do_i2c 1|0
raspi-config nonint get_serial
raspi-config nonint get_serial_hw
raspi-config nonint do_serial 1|0
raspi-config nonint get_onewire
raspi-config nonint do_onewire 1|0
raspi-config nonint get_rgpio
raspi-config nonint do_rgpio 1|0
raspi-config nonint get_blanking
raspi-config nonint do_blanking 1|0
raspi-config nonint get_pi_type
raspi-config nonint is_pi
raspi-config nonint is_pifour
raspi-config nonint is_fkms
raspi-config nonint get_config_var arm_freq /boot/config.txt
raspi-config nonint do_overclock None|Modest|Medium|High|Turbo
raspi-config nonint get_config_var gpu_mem /boot/config.txt
raspi-config nonint get_config_var gpu_mem_256 /boot/config.txt
raspi-config nonint get_config_var gpu_mem_512 /boot/config.txt
raspi-config nonint get_config_var gpu_mem_1024 /boot/config.txt
raspi-config nonint do_memory_split 16|32|64|128|256
raspi-config nonint get_config_var hdmi_group /boot/config.txt
raspi-config nonint get_config_var hdmi_mode /boot/config.txt
raspi-config nonint get_wifi_country
# find wifi countries here /usr/share/zoneinfo/iso3166.tab
raspi-config nonint do_wifi_country "yourcountry"
raspi-config nonint do_pi4video V1
raspi-config nonint do_pi4video V2
raspi-config nonint do_pi4video V3
raspi-config nonint get_pi4video
raspi-config nonint get_overlay_now
raspi-config nonint get_overlay_conf
raspi-config nonint get_bootro_conf
raspi-config nonint enable_overlayfs
raspi-config nonint disable_overlayfs
raspi-config nonint enable_bootro
raspi-config nonint disable_bootro
raspi-config nonint is_uname_current
raspi-config nonint list_wlan_interfaces
raspi-config nonint is_installed realvnc-vnc-server
raspi-config nonint is_installed xscreensaver

vcgencmd

Also the vcgencmd CLI tool is good to knonw

vcgencmd commands list the available commands

Get the board temperature with vcgencmd measure_temp

To get the allocated GPU use vcgencmd get_mem gpu | cut -d = -f 2 | cut -d M -f 1

First let's install some dependencies

sudo apt-get install gstreamer-tools gstreamer1.0-plugins-bad gstreamer1.0-plugins-good

Server will open the raspivid cli tool and pipe on stdout, streamer will take the input and parse h264 and stream as rtp

raspivid -t 0 -h 720 -w 1080 -fps 25 -hf -b 2000000 -o - | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5000

Client will open a window displaying the video feedback

gst-launch-1.0 -v tcpclientsrc host=<pi4-ip> port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false

Credits

Based on the article from raspberry-projects.com

I bought this matrix array keypad for my door opener but had no luck in finding a working library for NodeMCU in micropython.

I wrote a simple one inspired from Chris—A/Keypad

The repository is muka/micropython-nodemcu-maxtix-keypad

I have an old door which is in urge of some smartness.

Materials

  1. nodemcu
  2. a relay
  3. a door lock
  4. an AV to 12v converter
  5. an pin keypad [coming soon]

Sources

button

The code is on muka/door-opener

It contains some scripts to get started and the codebase for the nodemcu

Hardware setup

Based on this post most pins are high at boot and should not be set to low to avoid boot issues.

Considering our door should not open if there is a power outage the control ping will be GPIO5. Power and ground can be a 3.3v and GND pin

Connection pf the nodeMcU to the relay Relay

To connect the relay to the 12v adapter

  • NO goes to 12v +
  • CTRL goes to 12v -

switch web interface

This code is based on the Random Nerd Tutorial post

It exposes a webpage with a button that point to a query string such as ?switch=led. Based on the current GPIO state it switch on or off the led.


import socket
import network
import time
from machine import Pin

WIFI_SSID = "..."
WIFI_PASS = "..."

def connect_wifi():
    print("Connecting to " + WIFI_SSID)
    station = network.WLAN(network.STA_IF)
    station.active(True)
    station.connect(WIFI_SSID, WIFI_PASS)
    while station.isconnected() == False:
        pass

    ifcfg = station.ifconfig()
    ip = ''
    if len(ifcfg) > 0:
        ip = ifcfg[0]
    print('wifi connected')
    return ip


def web_page(is_on):

    if not is_on:
        gpio_state = "OFF"
    else:
        gpio_state = "ON"

    html = """
<html>
    <head>
        <title>LED Switch</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            html { font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
            h1{color: #0F3376; padding: 2vh;}
            p{font-size: 1.5rem;}
            .button{display: inline-block; background-color: #336699; border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
            .button.OFF{ background-color: #333;}
        </style>
    </head>
    <body>
        <h1>LED Switch</h1>
        <p><a href="/?switch=led">
            <button class="button """ + gpio_state + """">Turn """ + gpio_state + """</button>
        </a></p>
    </body>
</html>"""

    return html


def http_server():

    led = Pin(2, Pin.OUT)
    led.off()

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('', 80))
    s.listen(5)

    while True:

        conn, addr = s.accept()

        request = conn.recv(1024)
        request = str(request)

        if len(request) == 0:
            continue

        lines = request.split("\\r\\n")
        if len(lines) == 0:
            continue
        line0 = lines[0]
        lines = None

        parts = line0.split(" ")
        if len(parts) < 3:
            continue

        method, path, http_ver = parts

        print('%s - %s %s' % (str(addr[0]), str(method), str(path)))

        is_on = led.value() == 1
        if path.find("switch=led") > -1:
            if is_on:
               led.off()
            else:
                led.on()
            is_on = (not is_on)

        response = web_page(is_on)
        conn.send('HTTP/1.1 200 OK\n')
        conn.send('Content-Type: text/html\n')
        conn.send('Connection: close\n\n')
        conn.sendall(response)
        conn.close()


def run():
    ip = connect_wifi()
    print('Listening on http://%s' % ip)
    http_server()


if __name__ == '__main__':
    run()

Based on the ESP-MicroPython codebase an example of a mqtt client.

The original example is here https://github.com/RuiSantosdotme/ESP-MicroPython/blob/master/code/MQTT/MQTT_Hello_World/ESP_1/main.py


from umqttsimple import MQTTClient
import network
import ubinascii
import machine
import time


WIFI_SSID = "..."
WIFI_PASS = "..."
# server is test.mosquitto.org
MQTT_SERVER = "5.196.95.208"
MQTT_CLIENTID = "test"
MQTT_TOPIC = "hello-esp"


def sub_cb(topic, msg):
    print('ESP received hello message')
    print((topic, msg))


def connect_and_subscribe(mqtt_server, client_id, topic_sub):
    client = MQTTClient(ubinascii.hexlify(client_id), mqtt_server)
    client.set_callback(sub_cb)
    client.connect()
    client.subscribe(topic_sub)
    print('Connected to %s MQTT broker, subscribed to %s topic' %
          (mqtt_server, topic_sub))
    return client


def restart_and_reconnect():
    print('Failed to connect to MQTT broker. Reconnecting...')
    time.sleep(10)
    machine.reset()


def connect_mqtt(mqtt_server, client_id, topic_sub):
    try:
        client = connect_and_subscribe(mqtt_server, client_id, topic_sub)
    except OSError as err:
        restart_and_reconnect()

    counter = 0
    message_interval = 10
    last_message = 0

    while True:
        try:
            client.check_msg()
            if (time.time() - last_message) > message_interval:
                msg = b'Hello #%d' % counter
                client.publish(topic_sub, msg)
                last_message = time.time()
                counter += 1
        except OSError as err:
            print("restarting, err", err)
            restart_and_reconnect()


def connect_wifi():
    print("Connecting to " + WIFI_SSID)
    station = network.WLAN(network.STA_IF)
    station.active(True)
    station.connect(WIFI_SSID, WIFI_PASS)
    while station.isconnected() == False:
        pass
    print('wifi connected')
    print(station.ifconfig())


def run():
    connect_wifi()
    connect_mqtt(MQTT_SERVER, MQTT_CLIENTID, MQTT_TOPIC)


if __name__ == '__main__':
    run()


I have bought a CQRobot Metal DC Geared Motor w/Encoder with Metal Mounting Bracket -12V/40RPM /80Kg.cm

From the specs:

This is a Gear Motor w/Encoder, Support 6V and 12V working voltage, for Projects Such as Robot, Custom Servo, Arduino and 3D Printers.

The schematics suggested

The nodeMCU has this pinout

node MCU pinout

I used this nice class from OutOfCheeseError to control the motor.

from machine import Pin, ADC, PWM

class DCMotor:
    def __init__(self, pwm_pin, direction_pin1, direction_pin2):
        """
        pwm_pin: PWM capable pin id. This pin should be connected to ENA/B.
        direction_pin1 and direction_pin1: Direction pins to be connected to
                                           N1/2 or N3/4.
        """
        self.dir_pin1 = Pin(direction_pin1, mode=Pin.OUT)
        self.dir_pin2 = Pin(direction_pin2, mode=Pin.OUT)
        self.pwm_pin = Pin(pwm_pin, mode=Pin.OUT)
        self.pwm = PWM(self.pwm_pin, freq=100, duty=0)

    def forward(self):
        self.dir_pin1.on()
        self.dir_pin2.off()

    def backward(self):
        self.dir_pin1.off()
        self.dir_pin2.on()

    def stop(self):
        self.dir_pin1.off()
        self.dir_pin2.off()

    def set_speed(self, ratio):
        """
        sets speed by pwm duty cycle value.
        ratio: The speed ratio ranging from 0 to 1.
               Anything above 1 will be taken as 1 and negative
               as 0.
        """
        if ratio < 0:
            self.pwm.duty(0)
        elif ratio <= 1.0:
            self.pwm.duty(int(1024*ratio))
        else:
            self.pwm.duty(1024)


# D1,D2, D3
motor = DCMotor(5, 4, 0)

print("forward")
motor.forward()
motor.set_speed(0)
sleep(5)
motor.set_speed(0.5)

print("backward")
sleep(5)
motor.backward()
motor.set_speed(1)

print("stop")
sleep(2)
motor.set_speed(0)
motor.stop()

  1. CTRL+, for the settings page
  2. Go to packages
  3. Search tree-view core package
  4. Untick Hide VCS Ignored Files

screenshot