HTTPClients are reusable

Hi 👋,

I wanted to write this article to tell you that instantiating a HttpClient class is often a costly operation.

If you have a method that does something like:

public class Main {
  static void myMethod() {
    HttpClient client = new HttpClient()
    // do stuff
  }
}

You should refactor it ASAP. Either move the HttpClient into the class and perhaps ensure that the class is a Singleton or retrieve the HttpClient instance using an Object Pool pattern like the HttpClient class from System.Net.Http.

The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

Thanks for reading!

Further reading

Go Pattern: Sorting a slice on multiple keys

Hi 👋

In this article I want to highlight a simple pattern for sorting a slice in Go on multiple keys.

Given the following structure, let’s say we want to sort it in ascending order after Version, Generation and Time.

type TheStruct struct {
	Generation int
	Time       int
	Version    int
}

The way we sort slices in Go is by using the sort interface or one of the sort.Slice functions. To sort the slice after the above criteria we’ll call slice.Sort with the following function.

	sort.Slice(structs, func(i, j int) bool {
		iv, jv := structs[i], structs[j]
		switch {
		case iv.Version != jv.Version:
			return iv.Version < jv.Version
		case iv.Generation != jv.Generation:
			return iv.Generation < jv.Generation
		default:
			return iv.Time < jv.Time
		}
	})

The slice will be sorted after the following fields: Version, Generation and Time. The trick is the switch statement and the case expression case iv.Version != jv.Version followed by the statement return iv.Version < jv.Version.

You can use this pattern whenever you want to sort slices over multiple fields in Go.

Thanks for reading! 🍻

Source Code

package main

import (
	"fmt"
	"sort"
)

type TheStruct struct {
	Generation int
	Time       int
	Version    int
}

func main() {
	var structs = []TheStruct{
		{
			Generation: 1,
			Time:       150,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       200,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       200,
			Version:    2,
		},
		{
			Generation: 1,
			Time:       500,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       100,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       400,
			Version:    0,
		},
		{
			Generation: 2,
			Time:       400,
			Version:    0,
		},
		{
			Generation: 2,
			Time:       100,
			Version:    2,
		},
		{
			Generation: 1,
			Time:       300,
			Version:    0,
		},
	}

	fmt.Printf("%v\n", structs)

	sort.Slice(structs, func(i, j int) bool {
		iv, jv := structs[i], structs[j]
		switch {
		case iv.Version != jv.Version:
			return iv.Version < jv.Version
		case iv.Generation != jv.Generation:
			return iv.Generation < jv.Generation
		default:
			return iv.Time < jv.Time
		}
	})
	fmt.Printf("%v\n", structs)

}

Output

[{1 150 0} {1 200 0} {1 200 2} {1 500 0} {1 100 0} {1 400 0} {2 400 0} {2 100 2} {1 300 0}]
[{1 100 0} {1 150 0} {1 200 0} {1 300 0} {1 400 0} {1 500 0} {2 400 0} {1 200 2} {2 100 2}]

Also, special thanks to RP.💖

Multiple Python versions on Windows

Hi 👋

In this short article I will show you two ways of changing Python versions on Windows. It is useful when you have installed multiple Python versions on your system and want to run a specific version from the terminal.

For example, if we have the following versions installed:

We can use either the Python Launcher py to run Python or the python command.

Python Launcher

To list installed Python versions with Python launcher we can use the py -0 command.

@nutiu ➜ ~ py -0
Installed Pythons found by C:\WINDOWS\py.exe Launcher for Windows
 -3.10-64 *
 -3.7-64

@nutiu ➜ ~ py
Python 3.10.3 (tags/v3.10.3:a342a49, Mar 16 2022, 13:07:40) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

The default version has a star next to it. If we run a simple py command, we’ll get a prompt to Python 3.10. To change the default version all we need to do is to set the environment variable PY_PYTHON to the desired version.

@nutiu ➜ ~ $env:PY_PYTHON = "3.7"
@nutiu ➜ ~ py -0
Installed Pythons found by C:\WINDOWS\py.exe Launcher for Windows
 -3.10-64
 -3.7-64 *
@nutiu ➜ ~ py
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Using the Python command

If you prefer running Python using the full command then you’ll get the Python version which has higher precedence in your path, for example if I run python on my machine I will get:

@nutiu ➜ ~ python
Python 3.10.3 (tags/v3.10.3:a342a49, Mar 16 2022, 13:07:40) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

We can change the order by going to: My PC -> Advanced System Settings -> Environment Variables

Select path from User variables and click Edit…

Python 3.10 has higher precedence in path because it is above Python 3.7. If we want to change the order, we need to select the folders referencing Python37 and click Move Up until they are above Python 3.10

Restarting your terminal and running python again should run your desired Python version.

Thanks for reading! 🍻

A custom HomeKit accessory with Python

Hi 👋,

In this short article I want to showcase how I implemented a custom HomeKit accessory with python.

My Home Assistant’s SD card died 🪦 a few days ago and the support for GPIO based sensors will be removed in newer releases. This makes it unsuitable for my needs, while giving me the perfect opportunity to try other things.

To continue monitoring temperature and humidity in my home I’ve built a custom HomeKit accessory with HAP Python.

The Sensor

A BME680 air quality sensor is used to monitor temperature and humidity. It is connected to the PI according to the following diagram:

The communication with the Pi is done using the I2C protocol. If you want to use I2C in your own setup, it has to be enabled using raspi-config, as it doesn’t come enabled by default.

# Execute
sudo raspi-config
# Then select Interfacing options->I2C and enable it.

Connection can be tested with the following command:

sudo apt-get install build-essential libi2c-dev i2c-tools python-dev libffi-dev git
/usr/sbin/i2cdetect -y 1
pi@raspberrypi:~ $ 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 -- 

It will output the address that the sensor is using, in our case the 0x76 I2C address.

The Code for the Accessory

You can browse the full code for the accessory and bme680 sensor in my git repo.

To run the program, clone the repository and ensure that you’re running it under the pi user, otherwise you will need to change some things.

cd /home/pi && git clone git@github.com:dnutiu/bme680-homekit.git && cd bme680-homekit
sudo apt-get install libavahi-compat-libdnssd-dev
pip3 install -r requirements.txt

Verify that the program works by running python3 main.py. Running it the first time will prompt you to add the accessory to the Home app. If you miss this step you can repeat it by deleting the accessory.state file located in pi’s home directory and by running the program again.

After you’ve verified that it works, you can setup a systemd service to run the accessory’s python script when the PI boots

Copy the bme680-homekit.service to /etc/systemd/system and check that the service is running.

sudo cp bme680-homekit.service /etc/systemd/system
sudo systemctl status bme680-homekit

If you want to run this under another user rather than the pi, you’ll need to tweak the bme680-homekit.service file.

Congratulations for making it this far! 🎉

You can browse more code examples in the HAP-Python repository.

Thanks for reading and have fun! 👩‍💻👨‍💻 ⚙️