func main() {
	log.Println("Started Meter Receiver Server")

	//Listen to the TCP port for connections from meter readers
	updatechan := make(chan *MeterReader.CounterUpdate)
	settingschan := make(chan *MeterReader.Settings)

	go func() {
		// drain the channel for settings which we won't need
		for range settingschan {
		}
	}()

	log.Println("Listening to port 2110 for meter events")
	listener, err := net.Listen("tcp", "127.0.0.1:2110")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			if conn, err := listener.Accept(); err == nil {
				//If err is nil then that means that data is available for us so we take up this data and pass it to a new goroutine
				go MeterReader.HandleProtoClient(conn, updatechan, settingschan)
			} else {
				continue
			}
		}
	}()

	// Listen to the serial port
	go func() {

		for {

			serialPorts, err := filepath.Glob("/dev/ttyUSB*")

			if err == nil {
				for i := range serialPorts {
					config := &serial.Config{Name: serialPorts[i], Baud: 57600}
					ser, err := serial.OpenPort(config)

					if err != nil {
						// ok, try the next port
					} else {
						log.Printf("Opened port %s", serialPorts[i])
						MeterReader.HandleProtoClient(ser, updatechan, settingschan)
					}
				}
			}

			time.Sleep(time.Second) // try to open again in a second
		}
	}()

	// translate the events from the meters to meter state messages
	msh := MeterReader.NewMeterStateHandler()
	tch := msh.Handle(updatechan)

	// socket.io server
	log.Println("Starting socket.io server")
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}
	server.On("connection", func(so socketio.Socket) {
		log.Println("on connection")
		so.Join("updates")
		so.On("disconnection", func() {
			log.Println("on disconnect")
		})
	})
	server.On("error", func(so socketio.Socket, err error) {
		log.Println("error:", err)
	})
	go func() {
		for msg := range tch {
			log.Println("JSON to UI:", msg)
			server.BroadcastTo("updates", "meter update", msg)
		}
	}()

	// serve the user
	log.Println("Preparing json api")
	api := MeterReader.MakeAPI()

	http.Handle("/api/", http.StripPrefix("/api", api.MakeHandler()))
	http.Handle("/socket.io/", server)
	http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("src/MeterReader/static"))))

	go func() {
		log.Println("Listening on port 2111 for http traffic")
		log.Fatal(http.ListenAndServe(":2111", nil))
	}()

	// stop on SIGINT and SIGTERM
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	log.Println(<-ch)
}
Exemplo n.º 2
0
func main() {
	var serialport = flag.String("serial", "/dev/ttyUSB0", "The serial port to use to connect")
	var id = flag.Uint("id", math.MaxUint32, "Set the meter id")
	var seriesId = flag.Uint("series", 0, "Set the series id")
	var calibrate = flag.Bool("calibrate", false, "Start calibration")
	var uncalibrate = flag.Bool("uncalibrate", false, "Reset calibration values")
	var serialProtocol = flag.Bool("serialproto", false, "Use serial communication to transfer updates")
	var wirelessProtocol = flag.Bool("wirelessproto", false, "Use wireless to transfer updates")
	var risingEdgeAmounts edgeAmounts
	var fallingEdgeAmounts edgeAmounts
	flag.Var(&risingEdgeAmounts, "rising", "Rising edge amount")
	flag.Var(&fallingEdgeAmounts, "falling", "Falling edge amount")

	flag.Parse()

	config := &serial.Config{Name: *serialport, Baud: 57600}
	// Opening the port resets the device. First the bootloader runs for half a second, then the actual application loads.
	// Wait for this to happen before attempting to talk to the device.
	time.Sleep(1 * time.Second)

	updatechan := make(chan *MeterReader.CounterUpdate)
	settingschan := make(chan *MeterReader.Settings)

	go func() {
		// drain the channel for updates which we won't need
		for range updatechan {
		}
	}()

	ser, err := serial.OpenPort(config)

	if err != nil {
		log.Fatal(err)
	}

	go MeterReader.HandleProtoClient(ser, updatechan, settingschan)

	log.Print("Waiting for current settings")
	settings := <-settingschan
	log.Print("Got current settings")

	MeterReader.PrintSettings(settings)

	log.Print("id=", *id)

	changedSettings := false
	expectSettingsResponse := false

	if *calibrate {
		expectSettingsResponse = true
		MeterReader.SendStartCalibration(ser)
	}

	if *id != math.MaxUint32 {
		changedSettings = true
		var _id = uint32(*id)
		settings.MeterId = &_id
	}

	if *seriesId != 0 {
		changedSettings = true
		var _id = uint32(*seriesId)
		settings.SeriesId = &_id
	}

	if fallingEdgeAmounts.changed || risingEdgeAmounts.changed {
		if fallingEdgeAmounts.sensors != risingEdgeAmounts.sensors {
			log.Fatal("Number of rising and falling edge amounts must be the same.")
		}

		if fallingEdgeAmounts.sensors > 6 {
			log.Fatal("Maximum 6 edges allowed.")
		}

		settings.FallingEdgeAmounts = fallingEdgeAmounts.amounts
		settings.RisingEdgeAmounts = risingEdgeAmounts.amounts

		changedSettings = true
	}

	if *uncalibrate {
		settings.FallingEdgeAmounts = []uint32{0, 0, 0, 0, 0, 0}
		settings.RisingEdgeAmounts = []uint32{0, 0, 0, 0, 0, 0}
		changedSettings = true
	}

	if *serialProtocol || *wirelessProtocol {
		if *serialProtocol && *wirelessProtocol {
			log.Fatal("Can't use both serial and wireless communication protocol.")
		}

		var mode MeterReader.Settings_CommunicationChannel
		if *serialProtocol {
			mode = MeterReader.Settings_SERIAL
		} else {
			mode = MeterReader.Settings_WIRELESS
		}
		settings.CommunicationChannel = &mode
		changedSettings = true
	}

	if changedSettings {
		MeterReader.PrintSettings(settings)
		MeterReader.SendSettings(ser, settings)
		expectSettingsResponse = true
	}

	if expectSettingsResponse {
		MeterReader.PrintSettings(<-settingschan)
	}
}