fermentord/internal/lcd/hd44780.go

205 lines
3.9 KiB
Go
Raw Normal View History

2022-03-15 20:07:53 +00:00
package lcd
import (
"context"
"fmt"
2022-07-24 07:38:40 +00:00
"log"
2022-03-15 20:07:53 +00:00
"sync"
2022-07-24 07:38:40 +00:00
"time"
2022-03-15 20:07:53 +00:00
2024-06-15 14:31:02 +00:00
"git.joco.dk/snr/fermentord/internal/controllers"
"git.joco.dk/snr/fermentord/pkg/temperature"
2022-03-15 20:07:53 +00:00
device "github.com/d2r2/go-hd44780"
"github.com/d2r2/go-i2c"
2022-07-25 08:55:25 +00:00
"github.com/getsentry/sentry-go"
2022-03-15 20:07:53 +00:00
)
type LCD struct {
ambient, chamber, setpoint, wort float64
state string
bus *i2c.I2C
lcd *device.Lcd
l1, l2 string
chTemp chan temperature.TemperatureReading
chState chan controllers.ChamberState
chSetpoint chan float64
2022-07-24 07:38:40 +00:00
lastUpdate time.Time
2022-07-25 08:55:25 +00:00
hub *sentry.Hub
2022-03-15 20:07:53 +00:00
}
2024-06-15 14:26:28 +00:00
func NewLCD(bus int) (*LCD, error) {
2022-03-15 20:07:53 +00:00
var err error
p := &LCD{
chTemp: make(chan temperature.TemperatureReading, 10),
chState: make(chan controllers.ChamberState, 10),
chSetpoint: make(chan float64, 10),
2022-07-24 07:38:40 +00:00
lastUpdate: time.Now(),
2022-07-25 08:55:25 +00:00
hub: sentry.CurrentHub().Clone(),
2022-03-15 20:07:53 +00:00
}
2024-06-15 14:26:28 +00:00
p.bus, err = i2c.NewI2C(0x27, bus)
2022-03-15 20:07:53 +00:00
if err != nil {
return nil, err
}
p.lcd, err = device.NewLcd(p.bus, device.LCD_16x2)
if err != nil {
p.bus.Close()
return nil, err
}
2024-06-15 14:26:28 +00:00
err = p.lcd.BacklightOn()
if err != nil {
p.bus.Close()
return nil, err
}
err = p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1)
if err != nil {
p.bus.Close()
return nil, err
}
err = p.lcd.ShowMessage("Initializing", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING)
2022-03-15 20:07:53 +00:00
if err != nil {
p.bus.Close()
return nil, err
}
return p, nil
}
func (p *LCD) Close() error {
2022-07-24 07:38:40 +00:00
if err := p.lcd.BacklightOff(); err != nil {
2022-07-25 08:55:25 +00:00
p.hub.CaptureException(err)
2022-07-24 07:38:40 +00:00
log.Print(err)
}
2022-08-02 18:59:27 +00:00
p.hub.Flush(10 * time.Second)
2022-03-15 20:07:53 +00:00
return p.bus.Close()
}
func (p *LCD) SetTemperature(t temperature.TemperatureReading) {
2022-07-25 08:55:25 +00:00
select {
case p.chTemp <- t:
break
default:
err := fmt.Errorf("channel overflow on display temperature channel")
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
}
func (p *LCD) SetSetpointTemp(t float64) {
2022-07-25 08:55:25 +00:00
select {
case p.chSetpoint <- t:
break
default:
err := fmt.Errorf("channel overflow on display setpoint temperature channel")
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
}
func (p *LCD) SetState(state controllers.ChamberState) {
2022-07-25 08:55:25 +00:00
select {
case p.chState <- state:
break
default:
err := fmt.Errorf("channel overflow on display state channel")
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
}
func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case t := <-p.chTemp:
p.ambient = t.Ambient
p.chamber = t.Chamber
p.wort = t.Wort
2022-07-25 08:55:25 +00:00
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
case state := <-p.chState:
switch state {
case controllers.ChamberStateIdle:
p.state = "Id"
case controllers.ChamberStateHeating:
p.state = "He"
case controllers.ChamberStateCooling:
p.state = "Co"
}
2022-07-25 08:55:25 +00:00
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
case t := <-p.chSetpoint:
p.setpoint = t
2022-07-25 08:55:25 +00:00
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
2022-07-25 08:55:25 +00:00
case <-ctx.Done():
if err := p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1|device.SHOW_BLANK_PADDING); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
if err := p.lcd.ShowMessage("Shutting down", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
2022-03-15 20:07:53 +00:00
return
}
}
}
func (p *LCD) update() error {
2022-07-24 07:38:40 +00:00
if time.Since(p.lastUpdate) < 3*time.Second {
return nil
}
2022-03-15 20:07:53 +00:00
l1 := fmt.Sprintf("W:%4.1f C:%4.1f %s", p.wort, p.chamber, p.state)
l2 := fmt.Sprintf("S:%4.1f A:%4.1f", p.ambient, p.setpoint)
if l1 != p.l1 {
if err := p.lcd.ShowMessage(l1, device.SHOW_LINE_1|device.SHOW_BLANK_PADDING); err != nil {
return err
}
p.l1 = l1
}
if l2 != p.l2 {
if err := p.lcd.ShowMessage(l2, device.SHOW_LINE_2|device.SHOW_BLANK_PADDING); err != nil {
return err
}
p.l2 = l2
}
2022-07-24 07:38:40 +00:00
p.lastUpdate = time.Now()
2022-03-15 20:07:53 +00:00
return nil
}