Esempio n. 1
0
// init runs before anything else, and loads the images for the LED pane
func init() {
	images = make(map[string]util.Image)
	images["logo"] = util.LoadImage(util.ResolveImagePath("twitter-bird.png"))
	images["animated"] = util.LoadImage(util.ResolveImagePath("twitter-animated.gif"))
	images["error"] = util.LoadImage(util.ResolveImagePath("errorX.gif"))
	images["at"] = util.LoadImage(util.ResolveImagePath("at.gif"))
	images["tick"] = util.LoadImage(util.ResolveImagePath("tick.gif"))
}
func NewWeatherPane(conn *ninja.Connection) *WeatherPane {

	pane := &WeatherPane{
		siteModel: conn.GetServiceClient("$home/services/SiteModel"),
		image:     util.LoadImage(util.ResolveImagePath("weather/loading.gif")),
	}

	pane.tempTimeout = time.AfterFunc(0, func() {
		pane.temperature = false
	})

	if !enableWeatherPane {
		return pane
	}

	var err error
	pane.weather, err = owm.NewForecast("C")
	if err != nil {
		log.Warningf("Failed to load weather api:", err)
		enableWeatherPane = false
	} else {
		go pane.GetWeather()
	}

	return pane
}
func (p *WeatherPane) GetWeather() {

	enableWeatherPane = false

	for {
		site := &model.Site{}
		err := p.siteModel.Call("fetch", config.MustString("siteId"), site, time.Second*5)

		if err == nil && (site.Longitude != nil || site.Latitude != nil) {
			p.site = site
			globalSite = site

			if site.TimeZoneID != nil {
				if timezone, err = time.LoadLocation(*site.TimeZoneID); err != nil {
					log.Warningf("error while setting timezone (%s): %s", *site.TimeZoneID, err)
					timezone, _ = time.LoadLocation("Local")
				}
			}
			break
		}

		log.Infof("Failed to get site, or site has no location.")

		time.Sleep(time.Second * 2)
	}

	for {

		p.weather.DailyByCoordinates(
			&owm.Coordinates{
				Longitude: *p.site.Longitude,
				Latitude:  *p.site.Latitude,
			},
			1,
		)

		if len(p.weather.List) > 0 {

			filename := util.ResolveImagePath("weather/" + p.weather.List[0].Weather[0].Icon + ".png")

			if _, err := os.Stat(filename); os.IsNotExist(err) {
				enableWeatherPane = false
				fmt.Printf("Couldn't load image for weather: %s", filename)
				bugsnag.Notify(fmt.Errorf("Unknown weather icon: %s", filename), p.weather)
			} else {
				p.image = util.LoadImage(filename)
				enableWeatherPane = true
			}
		}

		time.Sleep(weatherUpdateInterval)

	}

}
func NewOnOffPane(offImage string, onImage string, onStateChange func(bool), conn *ninja.Connection, thingType string) *OnOffPane {

	log := logger.GetLogger("OnOffPane")

	pane := &OnOffPane{
		onImage:       util.LoadImage(onImage),
		offImage:      util.LoadImage(offImage),
		onStateChange: onStateChange,
		log:           log,
		devices:       make([]*ninja.ServiceClient, 0),
		conn:          conn,
	}

	listening := make(map[string]bool)

	getChannelServicesContinuous(thingType, "on-off", nil, func(clients []*ninja.ServiceClient, err error) {
		if err != nil {
			log.Infof("Failed to update devices: %s", err)
		} else {
			log.Infof("Pane got %d on/off devices", len(clients))
			pane.devices = clients

			for _, device := range clients {
				if _, ok := listening[device.Topic]; !ok {
					listening[device.Topic] = true

					device.OnEvent("state", func(state *bool, topicKeys map[string]string) bool {
						log.Debugf("Got on-off state: %t", *state)

						if time.Since(pane.lastTap) > 1*time.Second {
							pane.state = *state
						}

						return true
					})
				}
			}
		}
	})

	return pane
}
func NewPairingCodePane(text string) *PairingCodePane {

	img := image.NewRGBA(image.Rect(0, 0, 16, 16))

	width := O4b03b.Font.DrawString(img, 0, 0, text, color.Black)
	//log.Printf("Text '%s' width: %d", text, width)

	return &PairingCodePane{
		text:      text,
		textWidth: width,
		image:     util.LoadImage(util.ResolveImagePath("code-underline.gif")),
	}
}
Esempio n. 6
0
// loadImages saves the PNG and GIF files in the images directory into the stateImages map
func loadImages() {
	files, err := ioutil.ReadDir("./images")

	if err != nil {
		panic("Couldn't load images: " + err.Error())
	}

	stateImages = make(map[string]util.Image)

	for _, f := range files {

		if strings.HasSuffix(f.Name(), ".gif") || strings.HasSuffix(f.Name(), ".png") {
			name := strings.TrimSuffix(strings.TrimSuffix(f.Name(), ".png"), ".gif")

			log.Infof("Found state image: " + name)
			stateImages[name] = util.LoadImage(util.ResolveImagePath(f.Name()))
			// also save names of images used as keys in images map
			stateImageNames = append(stateImageNames, name)
		}
	}
}
Esempio n. 7
0
func NewACPane(conn *ninja.Connection) *ACPane {

	pane := &ACPane{
		thermostat:  []*ninja.ServiceClient{},
		acstat:      []*ninja.ServiceClient{},
		mode:        "off",
		flash:       false,
		targetTemp:  666,
		currentTemp: 666,
		images: map[string]util.Image{
			"off":  util.LoadImage(util.ResolveImagePath("fan.gif")),
			"fan":  util.LoadImage(util.ResolveImagePath("fan-on.gif")),
			"cool": util.LoadImage(util.ResolveImagePath("fan-on-blue.gif")),
			"heat": util.LoadImage(util.ResolveImagePath("fan-on-red.gif")),
		},
	}

	pane.ignoreTapTimer = time.AfterFunc(0, func() {
		pane.ignoringTap = false
	})

	pane.sendTempTimer = time.AfterFunc(0, func() {
		for _, thermostat := range pane.thermostat {
			thermostat.Call("set", pane.targetTemp, nil, 0)
		}
	})

	listening := make(map[string]bool)

	isFlash := func(s string) bool {
		return s == "SUSPENDED"
	}

	onState := func(protocol, event string, cb func(params *json.RawMessage)) {
		ui.GetChannelServicesContinuous("aircon", protocol, func(thing *model.Thing) bool {
			return true
		}, func(devices []*ninja.ServiceClient, err error) {
			if err != nil {
				log.Infof("Failed to update %s device: %s", protocol, err)
			} else {
				log.Infof("Got %d %s devices", len(devices), protocol)

				for _, device := range devices {

					log.Debugf("Checking %s device %s", protocol, device.Topic)

					if _, ok := listening[device.Topic]; !ok {

						// New device
						log.Infof("Got new %s device: %s", protocol, device.Topic)

						if protocol == "thermostat" {
							pane.thermostat = append(pane.thermostat, device)
						}

						if protocol == "acstat" {
							pane.acstat = append(pane.acstat, device)
						}

						if protocol == "demandcontrol" {

							// only need to query for the initial notification - listener will pick up the rest

							go func() {
								var state StateChangeNotification
								err := device.Call("get", nil, &state, time.Second*10)
								if err != nil {
									log.Errorf("Failed to fetch state from demand control channel: %s", err)
								}

								// spew.Dump("Got demand state", state)

								pane.flash = isFlash(state.State)
							}()
						}

						listening[device.Topic] = true

						device.OnEvent(event, func(params *json.RawMessage, values map[string]string) bool {
							cb(params)

							return true
						})
					}
				}
			}
		})
	}

	onState("temperature", "state", func(params *json.RawMessage) {
		var temp float64
		err := json.Unmarshal(*params, &temp)
		if err != nil {
			log.Infof("Failed to unmarshal temp from %s error:%s", *params, err)
		}

		pane.currentTemp = int(temp)

		log.Infof("Got the temp %d", pane.currentTemp)
	})

	onState("thermostat", "state", func(params *json.RawMessage) {
		var temp float64
		err := json.Unmarshal(*params, &temp)
		if err != nil {
			log.Infof("Failed to unmarshal thermostat from %s error:%s", *params, err)
		}

		pane.targetTemp = int(temp)

		log.Infof("Got the thermostat %d", pane.targetTemp)
	})

	onState("acstat", "state", func(params *json.RawMessage) {
		var state channels.ACState
		err := json.Unmarshal(*params, &state)
		if err != nil {
			log.Infof("Failed to unmarshal acstat from %s error:%s", *params, err)
		}

		pane.mode = *state.Mode

		log.Infof("Got the ac mode %d", pane.mode)
	})

	onState("demandcontrol", "state", func(params *json.RawMessage) {

		// spew.Dump("demand/controlstate", params)

		var state StateChangeNotification
		err := json.Unmarshal(*params, &state)
		if err != nil {
			log.Infof("Failed to unmarshal demandstat state from %s error:%s", *params, err)
		}

		pane.flash = isFlash(state.State)

		log.Infof("Got the demandcontrol state %d", pane.mode)
	})

	go ui.StartSearchTasks(conn)

	return pane
}
func NewImagePane(image string) *ImagePane {
	return &ImagePane{
		image: util.LoadImage(image),
	}
}
Esempio n. 9
0
	"image/draw"
	"io/ioutil"
	"strings"
	"time"

	"fmt"
	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
	"github.com/ninjasphere/sphere-go-led-controller/util"
)

var tapInterval = time.Millisecond * 500
var introDuration = time.Millisecond * 1500

// load a particular image - for a 'logo' in this case
var imageLogo = util.LoadImage(util.ResolveImagePath("logo.png"))
var border = util.LoadImage(util.ResolveImagePath("border-green.gif"))

var stateImages map[string]util.Image
var stateImageNames []string

// loadImages saves the PNG and GIF files in the images directory into the stateImages map
func loadImages() {
	files, err := ioutil.ReadDir("./images")

	if err != nil {
		panic("Couldn't load images: " + err.Error())
	}

	stateImages = make(map[string]util.Image)
func NewMediaPane(conn *ninja.Connection) *MediaPane {
	log := logger.GetLogger("MediaPane")

	pane := &MediaPane{
		log:         log,
		conn:        conn,
		gestureSync: &sync.Mutex{},

		volumeImage:     util.LoadImage(mediaImages.Volume),
		volumeUpImage:   util.LoadImage(mediaImages.VolumeUp),
		volumeDownImage: util.LoadImage(mediaImages.VolumeDown),
		muteImage:       util.LoadImage(mediaImages.Mute),
		playImage:       util.LoadImage(mediaImages.Play),
		pauseImage:      util.LoadImage(mediaImages.Pause),
		stopImage:       util.LoadImage(mediaImages.Stop),
		nextImage:       util.LoadImage(mediaImages.Next),

		playingState: "stopped",

		lastVolumeTime: time.Now(),
		//lastAirWheelTime: time.Now(),
	}

	e := func(state string) func(params *json.RawMessage, values map[string]string) bool {
		return func(params *json.RawMessage, values map[string]string) bool {
			if !pane.ignoringTap {
				pane.log.Infof("Received control event. Setting playing state to %s", state)
				pane.playingState = state
			}
			return true
		}
	}

	listening := make(map[string]bool)

	getChannelServicesContinuous("mediaplayer", "media-control", nil, func(devices []*ninja.ServiceClient, err error) {

		if err != nil {
			log.Infof("Failed to update control devices: %s", err)
		} else {

			pane.controlDevices = devices

			log.Infof("Got %d media-control devices", len(devices))

			for _, device := range devices {
				if _, ok := listening[device.Topic]; !ok {
					listening[device.Topic] = true

					// New Device
					log.Infof("Got new control device: %s", device.Topic)

					device.OnEvent("playing", e("playing"))
					device.OnEvent("buffering", e("playing"))
					device.OnEvent("paused", e("paused"))
					device.OnEvent("stopped", e("stopped"))
				}
			}
		}

		if len(pane.controlDevices) == 0 {
			pane.volumeMode = true
			pane.log.Debugf("No control devices. Forcing volume mode.")
		}

	})

	getChannelServicesContinuous("mediaplayer", "volume", nil, func(devices []*ninja.ServiceClient, err error) {
		if err != nil {
			log.Infof("Failed to update volume devices: %s", err)
		} else {

			log.Infof("Got %d volume devices", len(devices))

			pane.volumeDevices = devices
			pane.volumeUpDownMode = false
			for _, device := range devices {
				if !isValueInList("set", device.SupportedMethods) && isValueInList("volumeUp", device.SupportedMethods) {
					pane.log.Infof("Volume up/down mode!")
					pane.volumeUpDownMode = true
				}
			}

			for _, device := range devices {

				log.Debugf("Checking volume device %s", device.Topic)

				if _, ok := listening[device.Topic]; !ok {
					listening[device.Topic] = true
					// New device
					pane.log.Infof("Got new volume device: %s supported: %v", device.Topic, device.SupportedMethods)

					device.OnEvent("state", func(params *json.RawMessage, values map[string]string) bool {
						if time.Since(pane.lastVolumeTime) > time.Millisecond*500 {

							var volume channels.VolumeState
							err := json.Unmarshal(*params, &volume)
							if err != nil {
								pane.log.Infof("Failed to unmarshal volume from %s error:%s", *params, err)
							}
							pane.volume = *volume.Level
						}
						return true
					})
				}
			}
		}

		if len(pane.controlDevices) == 0 {
			pane.volumeMode = true
			pane.log.Debugf("No control devices. Forcing volume mode.")
		}
	})

	pane.volumeModeReset = time.AfterFunc(0, func() {
		if len(pane.controlDevices) > 0 {
			pane.volumeMode = false
			pane.log.Debugf("Going back to volume mode")
		}
	})

	pane.ignoreTapTimer = time.AfterFunc(0, func() {
		pane.ignoringTap = false
	})

	pane.volumeUpDownTimer = time.AfterFunc(0, func() {
		pane.volumeUpDown = nil
	})

	return pane
}
func NewPairingColorPane(maskImage string, color color.Color) *PairingColorPane {
	return &PairingColorPane{
		image: &util.MaskImage{util.LoadImage(maskImage)},
		color: color,
	}
}
func NewUpdateProgressPane(progressImage string, loopingImage string) *UpdateProgressPane {
	return &UpdateProgressPane{
		progressImage: util.LoadImage(progressImage),
		loopingImage:  util.LoadImage(loopingImage),
	}
}
func NewLightPane(colorMode bool /*onOffDevices *[]*ninja.ServiceClient, airwheelDevices *[]*ninja.ServiceClient,*/, offImage string, onImage string, conn *ninja.Connection) *LightPane {

	name := "BrightnessPane"
	if colorMode {
		name = "ColorPane"
	}

	log := logger.GetLogger(name)

	log.Infof("Light rate: %s", colorInterval.String())

	pane := &LightPane{
		onEnable:         make(chan bool),
		colorMode:        colorMode,
		onImage:          util.LoadImage(onImage),
		offImage:         util.LoadImage(offImage),
		log:              log,
		conn:             conn,
		airWheelThrottle: &throttle{delay: colorInterval},
		lastTap:          time.Now(),
		gestureSync:      &sync.Mutex{},
	}

	if colorMode {
		pane.onOffState = true
	}

	listening := make(map[string]bool)

	if !colorMode {
		getChannelServicesContinuous("light", "on-off", /*func(thing *model.Thing) bool {
			isAccent := strings.Contains(strings.ToLower(thing.Name), "accent")
			return isAccent == demoAccentMode
			}*/nil, func(clients []*ninja.ServiceClient, err error) {
				if err != nil {
					log.Infof("Failed to update on-off devices: %s", err)
				} else {
					log.Infof("Got %d on/off devices", len(clients))
					pane.onOffDevices = &clients

					for _, device := range clients {
						if _, ok := listening[device.Topic]; !ok {
							listening[device.Topic] = true

							device.OnEvent("state", func(state *bool, topicKeys map[string]string) bool {
								log.Debugf("Got on-off state: %t", *state)
								// Ignore state updates if its within 500ms of a tap (which will update the display)
								if time.Since(pane.lastTap) > 500*time.Millisecond {
									pane.onOffState = *state
								}

								return true
							})
						}
					}
				}
			})
	}

	//if demoAccentMode {
	getChannelServicesContinuous("light", "core/batching", /*func(thing *model.Thing) bool {
		isAccent := strings.Contains(strings.ToLower(thing.Name), "accent")
		return isAccent == demoAccentMode
		}*/nil, func(clients []*ninja.ServiceClient, err error) {
			if err != nil {
				log.Infof("Failed to update batching devices: %s", err)
			} else {
				log.Infof("Fot %d batching devices", len(clients))
				pane.airwheelDevices = &clients
			}
		})
	//}

	if colorMode {
		getChannelServicesContinuous("light", "color", nil, func(clients []*ninja.ServiceClient, err error) {
			if err != nil {
				log.Infof("Failed to update color devices: %s", err)
			} else {
				for _, device := range clients {
					if _, ok := listening[device.Topic]; !ok {
						listening[device.Topic] = true

						device.OnEvent("state", func(state *channels.ColorState, topicKeys map[string]string) bool {
							log.Debugf("Got color state: %+v", *state)

							if state.Mode != "hue" {
								log.Warningf("Can't handle color mode: %s yet.", state.Mode)
								return true
							}

							// Ignore state updates if its within 2s of an airwheel (which will update the display)
							if time.Since(pane.lastAirWheelTime) > time.Second {
								pane.airWheelState = *state.Hue
							}

							return true
						})
					}
				}
			}
		})
	} else {
		getChannelServicesContinuous("light", "brightness", nil, func(clients []*ninja.ServiceClient, err error) {
			if err != nil {
				log.Infof("Failed to update brightness devices: %s", err)
			} else {
				for _, device := range clients {
					if _, ok := listening[device.Topic]; !ok {
						listening[device.Topic] = true

						device.OnEvent("state", func(state *float64, topicKeys map[string]string) bool {
							log.Infof("Got brightness state: %f", *state)

							// Ignore state updates if its within 2s of an airwheel (which will update the display)
							if time.Since(pane.lastAirWheelTime) > time.Second {
								pane.airWheelState = *state
							}

							return true
						})
					}
				}
			}
		})
	}

	return pane
}