Skip to content

Commit

Permalink
add SI units
Browse files Browse the repository at this point in the history
  • Loading branch information
schachmat committed Feb 23, 2016
1 parent cd7c11a commit 66bc761
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 58 deletions.
10 changes: 8 additions & 2 deletions backends/worldweatheronline.com.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ func wwoParseCond(cond wwoCond, date time.Time) (ret iface.Cond) {
}
ret.FeelsLikeC = cond.FeelsLikeC

ret.PrecipMM = cond.PrecipMM
if cond.PrecipMM != nil {
ret.PrecipM = new(float32)
*ret.PrecipM = *cond.PrecipMM / 1000
}

ret.Time = date
if cond.TmpTime != nil {
Expand All @@ -143,7 +146,10 @@ func wwoParseCond(cond wwoCond, date time.Time) (ret iface.Cond) {
ret.Time = time.Date(year, month, day, hour, min, 0, 0, time.UTC)
}

ret.VisibleDistKM = cond.VisibleDistKM
if cond.VisibleDistKM != nil {
ret.VisibleDistM = new(float32)
*ret.VisibleDistM = *cond.VisibleDistKM * 1000
}

if cond.WinddirDegree != nil && *cond.WinddirDegree >= 0 {
ret.WinddirDegree = new(int)
Expand Down
75 changes: 25 additions & 50 deletions frontends/ascii-art-table.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package frontends

import (
"flag"
"fmt"
"log"
"math"
Expand All @@ -16,7 +15,7 @@ import (
)

type aatConfig struct {
imperial bool
unit iface.UnitSystem
}

//TODO: replace s parameter with printf interface?
Expand All @@ -41,10 +40,6 @@ func aatPad(s string, mustLen int) (ret string) {
}

func (c *aatConfig) formatTemp(cond iface.Cond) string {
unit := map[bool]string{
false: "C",
true: "F",
}
color := func(temp float32) string {
colmap := []struct {
maxtemp float32
Expand All @@ -63,34 +58,29 @@ func (c *aatConfig) formatTemp(cond iface.Cond) string {
break
}
}

if c.imperial {
temp = (temp*18 + 320) / 10
}
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, int(temp))
t, _ := c.unit.Temp(temp)
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, int(t))
}

_, u := c.unit.Temp(0.0)

if cond.TempC == nil {
return aatPad(fmt.Sprintf("? °%s", unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("? %s", u), 15)
}

t := *cond.TempC
if cond.FeelsLikeC != nil {
fl := *cond.FeelsLikeC
if fl < t {
return aatPad(fmt.Sprintf("%s – %s °%s", color(fl), color(t), unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%s – %s %s", color(fl), color(t), u), 15)
} else if fl > t {
return aatPad(fmt.Sprintf("%s – %s °%s", color(t), color(fl), unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%s – %s %s", color(t), color(fl), u), 15)
}
}
return aatPad(fmt.Sprintf("%s °%s", color(t), unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%s %s", color(t), u), 15)
}

func (c *aatConfig) formatWind(cond iface.Cond) string {
unit := map[bool]string{
false: "km/h",
true: "mph",
}
windDir := func(deg *int) string {
if deg == nil {
return "?"
Expand All @@ -115,57 +105,41 @@ func (c *aatConfig) formatWind(cond iface.Cond) string {
}
}

if c.imperial {
spdKmph = (spdKmph * 1000) / 1609
}
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, int(spdKmph))
s, _ := c.unit.Speed(spdKmph)
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, int(s))
}

_, u := c.unit.Speed(0.0)

if cond.WindspeedKmph == nil {
return aatPad(windDir(cond.WinddirDegree), 15)
}
s := *cond.WindspeedKmph

if cond.WindGustKmph != nil {
if g := *cond.WindGustKmph; g > s {
return aatPad(fmt.Sprintf("%s %s – %s %s", windDir(cond.WinddirDegree), color(s), color(g), unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%s %s – %s %s", windDir(cond.WinddirDegree), color(s), color(g), u), 15)
}
}

return aatPad(fmt.Sprintf("%s %s %s", windDir(cond.WinddirDegree), color(s), unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%s %s %s", windDir(cond.WinddirDegree), color(s), u), 15)
}

func (c *aatConfig) formatVisibility(cond iface.Cond) string {
unit := map[bool]string{
false: "km",
true: "mi",
}
if cond.VisibleDistKM == nil {
if cond.VisibleDistM == nil {
return aatPad("", 15)
}
v := *cond.VisibleDistKM

if c.imperial {
v = (v * 621) / 1000
}
return aatPad(fmt.Sprintf("%d %s", int(v), unit[c.imperial]), 15)
v, u := c.unit.Distance(*cond.VisibleDistM)
return aatPad(fmt.Sprintf("%d %s", int(v), u), 15)
}

func (c *aatConfig) formatRain(cond iface.Cond) string {
unit := map[bool]string{
false: "mm",
true: "in",
}
if cond.PrecipMM != nil {
a := *cond.PrecipMM
if c.imperial {
a *= 0.039
}

if cond.PrecipM != nil {
v, u := c.unit.Distance(*cond.PrecipM)
if cond.ChanceOfRainPercent != nil {
return aatPad(fmt.Sprintf("%.1f %s | %d%%", a, unit[c.imperial], *cond.ChanceOfRainPercent), 15)
return aatPad(fmt.Sprintf("%.1f %s | %d%%", v, u, *cond.ChanceOfRainPercent), 15)
}
return aatPad(fmt.Sprintf("%.1f %s", a, unit[c.imperial]), 15)
return aatPad(fmt.Sprintf("%.1f %s", v, u), 15)
} else if cond.ChanceOfRainPercent != nil {
return aatPad(fmt.Sprintf("%d%%", *cond.ChanceOfRainPercent), 15)
}
Expand Down Expand Up @@ -371,10 +345,11 @@ func (c *aatConfig) printDay(day iface.Day) (ret []string) {
}

func (c *aatConfig) Setup() {
flag.BoolVar(&c.imperial, "aat-imperial", false, "aat frontend: use imperial units for output")
}

func (c *aatConfig) Render(r iface.Data) {
func (c *aatConfig) Render(r iface.Data, unitSystem iface.UnitSystem) {
c.unit = unitSystem

fmt.Printf("Weather for %s\n\n", r.Location)
stdout := colorable.NewColorableStdout()

Expand Down
66 changes: 61 additions & 5 deletions iface/iface.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package iface

import (
"time"
"log"
)

type WeatherCode int
Expand Down Expand Up @@ -51,11 +52,11 @@ type Cond struct {
// range [0, 100].
ChanceOfRainPercent *int

// PrecipMM is the precipitation amount. It must be >= 0.
PrecipMM *float32
// PrecipM is the precipitation amount in meters(!). It must be >= 0.
PrecipM *float32

// VisibleDistKM is the visibility range in kilometers. It must be >= 0.
VisibleDistKM *float32
// VisibleDistM is the visibility range in meters(!). It must be >= 0.
VisibleDistM *float32

// WindspeedKmph is the average wind speed in kilometers per second.
WindspeedKmph *float32
Expand Down Expand Up @@ -103,14 +104,69 @@ type Data struct {
Location string
}

type UnitSystem int

const (
UnitsMetric UnitSystem = iota
UnitsImperial
UnitsSi
)

func (u UnitSystem) Temp(tempC float32) (res float32, unit string) {
if u == UnitsMetric {
return tempC, "°C"
} else if u == UnitsImperial {
return tempC*1.8 + 32, "°F"
} else if u == UnitsSi {
return tempC + 273.16, "°K"
}
log.Fatalln("Unknown unit system:", u)
return
}

func (u UnitSystem) Speed(spdKmph float32) (res float32, unit string) {
if u == UnitsMetric {
return spdKmph, "km/h"
} else if u == UnitsImperial {
return spdKmph/1.609, "mph"
} else if u == UnitsSi {
return spdKmph/3.6, "m/s"
}
log.Fatalln("Unknown unit system:", u)
return
}

func (u UnitSystem) Distance(distM float32) (res float32, unit string) {
if u == UnitsMetric || u == UnitsSi {
if distM < 1 {
return distM*1000, "mm"
} else if distM < 1000 {
return distM, "m"
} else {
return distM/1000, "km"
}
} else if u == UnitsImperial {
res, unit = distM/0.0254, "in"
if res < 3 * 12 { // 1yd = 3ft, 1ft = 12in
return
} else if res < 8 * 10 * 22 * 36 { //1mi = 8fur, 1fur = 10ch, 1ch = 22yd
return res / 36, "yd"
} else {
return res / 8 / 10 / 22 / 36, "mi"
}
}
log.Fatalln("Unknown unit system:", u)
return
}

type Backend interface {
Setup()
Fetch(location string, numdays int) Data
}

type Frontend interface {
Setup()
Render(weather Data)
Render(weather Data, unitSystem UnitSystem)
}

var (
Expand Down
11 changes: 10 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func main() {
// initialize global flags and default config
numdays := flag.Int("days", 3, "`NUMBER` of days of weather forecast to be displayed")
location := flag.String("city", "New York", "`LOCATION` to be queried")
unitSystem := flag.String("units", "metric", "`UNITSYSTEM` to use for output.\n \tChoices are: metric, imperial, si")
selectedBackend := flag.String("backend", "worldweatheronline.com", "`BACKEND` to be used")
selectedFrontend := flag.String("frontend", "ascii-art-table", "`FRONTEND` to be used")

Expand All @@ -57,10 +58,18 @@ func main() {
}
r := be.Fetch(*location, *numdays)

// set unit system
unit := iface.UnitsMetric
if *unitSystem == "imperial" {
unit = iface.UnitsImperial
} else if *unitSystem == "si" {
unit = iface.UnitsSi
}

// get selected frontend and render the weather data with it
fe, ok := iface.AllFrontends[*selectedFrontend]
if !ok {
log.Fatalf("Could not find selected frontend \"%s\"", *selectedFrontend)
}
fe.Render(r)
fe.Render(r, unit)
}

0 comments on commit 66bc761

Please sign in to comment.