3 Commits

Author SHA1 Message Date
gballan d4747ff559 [Issue #2] - adding code to verify a display is connected before attempting to use it
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2026-09-07 01:03:30 -04:00
gballan 20ba285263 [Issue #2] - adding initial support for SSD1306 displays
ci/woodpecker/push/woodpecker Pipeline was successful
2026-09-07 00:54:27 -04:00
gballan c60ef1c093 [Issue #1] - Adding UpdateInterval config value to set how long to wait in between each update loop, in seconds
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2026-09-07 00:34:29 -04:00
4 changed files with 59 additions and 3 deletions
+6
View File
@@ -1,5 +1,9 @@
package main
import (
"time"
)
const (
WifiSSID = "My Wifi Name"
WifiPass = "SecretWifiPassword"
@@ -12,4 +16,6 @@ const (
NodeName = "Studio Weather"
NodeID = "studio_env"
ClientID = "pico2w_studio_env"
UpdateInterval = 30 * time.Second
)
+3
View File
@@ -5,9 +5,12 @@ go 1.25.2
require (
github.com/soypat/cyw43439 v0.1.1
github.com/soypat/lneto v0.3.2
tinygo.org/x/drivers v0.36.0
tinygo.org/x/tinyfont v0.7.0
)
require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/soypat/seqs v0.0.0-20250124201400-0d65bc7c1710 // indirect
github.com/tinygo-org/pio v0.3.0 // indirect
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect
+6
View File
@@ -1,3 +1,5 @@
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/soypat/cyw43439 v0.1.1 h1:vcaTiVzfuz3keK7lJpVxStZ6tV8HCw7Ugzsh1k4mneE=
github.com/soypat/cyw43439 v0.1.1/go.mod h1:R2uSILRwSPmcmmKy5Z0FtK4ypgiPf5YqK+F+IKmXqxc=
github.com/soypat/lneto v0.3.2 h1:iUFeRSq2czT7Db6MMOsAnMCBlKCqvIr941zsNf9dcu0=
@@ -8,3 +10,7 @@ github.com/tinygo-org/pio v0.3.0 h1:opEnOtw58KGB4RJD3/n/Rd0/djYGX3DeJiXLI6y/yDI=
github.com/tinygo-org/pio v0.3.0/go.mod h1:wf6c6lKZp+pQOzKKcpzchmRuhiMc27ABRuo7KVnaMFU=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
tinygo.org/x/drivers v0.36.0 h1:F0x342A6GWqh6abtCa57uAxCyz/b9MbGzvIVvIf+gpE=
tinygo.org/x/drivers v0.36.0/go.mod h1:DQgKyHkB4G6IEOKVTAjApbKnWGwESN91EVJO+nMOE9Y=
tinygo.org/x/tinyfont v0.7.0 h1:Ju901eGRThlHLoti9K7myMYyv4phd3I0DrJwc14NTTU=
tinygo.org/x/tinyfont v0.7.0/go.mod h1:onflMSkpWl7r7j4MIqhPEVV39pn7yL4N3MOePl3G+G8=
+44 -3
View File
@@ -9,6 +9,11 @@ import (
"machine"
"strconv"
"time"
"image/color"
"tinygo.org/x/drivers/ssd1306"
"tinygo.org/x/tinyfont"
"tinygo.org/x/tinyfont/proggy"
)
var StateTopic = fmt.Sprintf("homeassistant/sensor/%s/state", NodeID)
@@ -292,10 +297,10 @@ func panicErr(msg string, err error) {
func main() {
time.Sleep(2 * time.Second)
// Configure I2C (Pin 16 SDA, Pin 17 SCL -> I2C0)
// Bump frequency to 400kHz for snappy display flushes
i2c := machine.I2C0
err := i2c.Configure(machine.I2CConfig{
Frequency: 100 * machine.KHz,
Frequency: 400 * machine.KHz,
SDA: machine.GPIO16,
SCL: machine.GPIO17,
})
@@ -303,6 +308,31 @@ func main() {
panicErr("I2C configuration", err)
}
// Instantiate nil oled variable
var oled *ssd1306.Device
// White color for display
white := color.RGBA{R: 255, G: 255, B: 255, A: 255}
// Probe address 0x3C with a zero-byte or 1-byte read
var dummy [1]byte
if err := i2c.ReadRegister(0x3C, 0x00, dummy[:]); err == nil {
println("SSD1306 detected at 0x3C")
dev := ssd1306.NewI2C(i2c)
dev.Configure(ssd1306.Config{
Address: 0x3C,
Width: 128,
Height: 64,
})
oled = dev
// Run some initial clearing and add booting text to the screen
oled.ClearBuffer()
tinyfont.WriteLine(oled, &proggy.TinySZ8pt7b, 0, 16, "Booting...", white)
oled.Display()
} else {
println("SSD1306 not found — running headless")
}
bme, err := NewBME280(i2c, BME280Addr)
if err != nil {
panicErr("BME280 init", err)
@@ -338,14 +368,25 @@ func main() {
if err != nil {
println("BME280 read error:", err.Error())
} else {
// Publish MQTT
stateJSON := fmt.Sprintf(`{"temperature":%.2f,"humidity":%.2f,"pressure":%.2f}`, t, h, p)
if err := mqtt.Publish(StateTopic, []byte(stateJSON), false); err != nil {
println("MQTT publish error:", err.Error())
} else {
println(fmt.Sprintf("[%s] Published: %s", NodeName, stateJSON))
}
// Render to OLED
if oled != nil {
oled.ClearBuffer()
tinyfont.WriteLine(oled, &proggy.TinySZ8pt7b, 0, 14, fmt.Sprintf("Node: %s", NodeName), white)
tinyfont.WriteLine(oled, &proggy.TinySZ8pt7b, 0, 30, fmt.Sprintf("Temp: %.1f C", t), white)
tinyfont.WriteLine(oled, &proggy.TinySZ8pt7b, 0, 46, fmt.Sprintf("Hum: %.1f %%", h), white)
tinyfont.WriteLine(oled, &proggy.TinySZ8pt7b, 0, 60, fmt.Sprintf("Pres: %.1f hPa", p), white)
oled.Display()
}
}
time.Sleep(30 * time.Second)
time.Sleep(UpdateInterval)
}
}