twchart

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 7, 2026 License: MIT Imports: 17 Imported by: 0

README

twchart

GitHub go.mod Go version (subdirectory of monorepo) GitHub Workflow Status License Go Reference

twchart is used to document and display sessions using a Thermoworks thermometer that is recorded in the cloud. Using the exported CSV of thermometer data, this program uses Apache ECharts to display other data on top of the graph.

The original inspiration and use-case for this was tracking bread-making since timing and temperature are important aspects of the process. On top of the timeseries temperature data, this is used to track different stages and adhoc notes throughout the process. In order to use it, you should track your notes using this flexible format, then POST to the server after the process is complete.

Notes format

The following format can be used to easily take time-based notes record stages. The server is able to parse this and display on top of a timeseries graph.

[Session Name]
Date: 2006-01-02

[Probe Name] Probe: 1
[Probe Name] Probe: [...]
[Probe Name] Probe: [n]

Note: 3:04PM: [Notes...]
[Stage Name]: 3:04PM
Note: 3:04PM: [Notes...]
[Stage Name]: 3:04PM

Done: 3:04PM
  • Dates and times here use Go's formatting conventions
  • 3:04PM timestamps can be replaced with elapsed durations (3m, 1h30m, etc.)
  • []: brackets above are placeholders for any text. Do not include the brackets. Do not use colons in text
  • Everything must be in chronological order
  • Notes and stages can happen at any time
  • You can have any number of notes and stages
Bread Example

Break-making is easy to track using timestamps since steps are pretty spread out.

Click to expand
Ciabatta
Date: 2025-05-24

Ambient Probe: 1
Oven Probe: 2

Note: 8:10PM: preparing to make biga

Preferment: 8:10PM
Note: 8:13PM: finished mixing biga

Bulk ferment: 7:00AM
Note: 8:00AM: 10 stretch and folds

Final Proof: 9:00AM
Note: 9:00AM: shaped dough

Bake: 10:30AM
Done: 10:55AM

Note: 12:00PM: bread is delicious and crunchy
Coffee Roasting Example

Coffee roasting happens pretty quickly, so it's easier to record durations instead of timestamps.

Click to expand
Coffee
Date: 2025-05-24

Ambient Probe: 1
Bean Probe: 2

Note: 8:00PM: preheat

Drying: 1m
Note: 1m: fan 9, heat 5

Maillard: 4m
Note: 4m: fan 7, heat 7

Development: 7m
Note: 7m: fan 5, heat 6
Note: 7m30s: first crack

Cooling: 8m30s

Done: 10m30s

Installation

go install github.com/calvinmclean/twchart/cmd/twchart@latest
docker pull ghcr.io/calvinmclean/twchart:latest

Usage

Run the server with existing data:

twchart serve --dir data/

This assumes you have a nested directory structure with .txt and .csv files with matching filenames (bread.txt/bread.csv)

See the docker-compose.yml file for an example using docker.

Uploading Data

Here is my process, but something else might work better for you.

  1. During baking/roasting/bbqing, record notes in a Notes app
  2. When it's done, use a Siri shortcut to make this request:
curl \
  -X POST \
  -H "Content-Type: text/plain" \
  --data-binary "@example.txt" \
  localhost:8080/sessions
  1. Download the exported CSV from Thermoworks Cloud and upload to the server with a Siri shortcut making this request:
curl \
  -X POST \
  -H "Content-Type: text/csv" \
  --data-binary "@example.csv" \
  localhost:8080/sessions/upload-csv
  • The /upload-csv endpoint will load the CSV data into the most recently-created Session

Documentation

Index

Constants

View Source
const (
	ProbePositionNone = iota
	ProbePosition1
	ProbePosition2
	ProbePosition3
	ProbePosition4
	ProbePosition5
)

Variables

This section is empty.

Functions

This section is empty.

Types

type DoneTime

type DoneTime time.Time

func (DoneTime) AddToSession

func (dt DoneTime) AddToSession(s *Session)

func (*DoneTime) UnmarshalJSON

func (dt *DoneTime) UnmarshalJSON(in []byte) error

type Event

type Event struct {
	Note string
	Time time.Time
}

func (Event) AddToSession

func (e Event) AddToSession(s *Session)

type Probe

type Probe struct {
	Name     string
	Position ProbePosition
}

func (Probe) AddToSession

func (p Probe) AddToSession(s *Session)

type ProbePosition

type ProbePosition uint

func (*ProbePosition) UnmarshalJSON

func (pp *ProbePosition) UnmarshalJSON(input []byte) error

func (*ProbePosition) UnmarshalText

func (pp *ProbePosition) UnmarshalText(input []byte) error

type Session

type Session struct {
	ID babyapi.ID

	Name      string
	Date      time.Time
	StartTime time.Time

	Probes []Probe
	Stages []Stage
	Events []Event

	Data []ThermoworksData

	UploadedAt time.Time
}

func (Session) Chart

func (s Session) Chart() (*charts.Line, error)

func (Session) ChartData

func (s Session) ChartData() [][]opts.LineData

func (*Session) FromText

func (s *Session) FromText(input []byte) error

FromText parses the input bytes into the Session struct

func (Session) GetID added in v0.2.0

func (s Session) GetID() string

func (*Session) LoadData

func (s *Session) LoadData(r io.Reader) error

func (*Session) LoadDataFromFile

func (s *Session) LoadDataFromFile(csvFile string) error

func (Session) TimeBounds

func (s Session) TimeBounds() (time.Time, time.Time)

TimeBounds returns the earliest and latest Events or Stages to set the bounds on the Chart

func (*Session) Write

func (s *Session) Write(p []byte) (int, error)

Write writes data from p into the Session struct

type SessionDate

type SessionDate time.Time

func (SessionDate) AddToSession

func (sd SessionDate) AddToSession(s *Session)

type SessionName

type SessionName string

func (SessionName) AddToSession

func (sn SessionName) AddToSession(s *Session)

type SessionPart

type SessionPart interface {
	AddToSession(*Session)
}

SessionPart is an interface that allows any parsed type to be applied to a Session

func ParseLine

func ParseLine(in []byte, currentDate, startTime time.Time) (SessionPart, time.Time, error)

type Stage

type Stage struct {
	Name     string
	Start    time.Time
	End      time.Time
	Duration time.Duration
}

func (Stage) AddToSession

func (s Stage) AddToSession(session *Session)

func (*Stage) Finish

func (s *Stage) Finish(t time.Time)

func (*Stage) MarkArea

func (s *Stage) MarkArea(color string) []opts.MarkAreaData

type ThermoworksData

type ThermoworksData struct {
	Time      time.Time
	ProbeData []float64
}

func (ThermoworksData) GetProbeData

func (td ThermoworksData) GetProbeData(pos ProbePosition) float64

Directories

Path Synopsis
cmd
twchart command
db

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL