コード例 #1
0
ファイル: wf_heartbeat.cs プロジェクト: bpaauwe/WFNodeServer
        internal void Updated(string address, int timestamp, WeatherFlow_UDP.DataType t)
        {
            // Check for missing data here.
            UDPTime  utime;
            TimeSpan epoch = DateTime.UtcNow - new DateTime(1970, 1, 1);

            utime.timestamp = timestamp;
            utime.now       = (int)epoch.TotalSeconds;

            if (!SecondsSinceUpdate.ContainsKey(address))
            {
                SecondsSinceUpdate[address] = utime;
            }

            // TODO: The diff should be 2x the interval. Is there some way to get that
            //       information here?
            int diff = timestamp - SecondsSinceUpdate[address].timestamp;

            switch (t)
            {
            case WeatherFlow_UDP.DataType.AIR:
            case WeatherFlow_UDP.DataType.SKY:
                // Expect data every 60 seconds
                if (diff >= 120)
                {
                    WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds");
                }
                break;

            case WeatherFlow_UDP.DataType.DEVICE:
                // Expect data every 60 seconds
                if (diff >= 90)
                {
                    WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds");
                }
                break;

            case WeatherFlow_UDP.DataType.HUB:
                // Expect data every 10 seconds
                if (diff >= 20)
                {
                    WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds");
                }
                break;

            case WeatherFlow_UDP.DataType.WIND:
                // Expect data every 3 seconds
                if (diff >= 6)
                {
                    WFLogging.Warning("Possible Missing data for " + address + ": " + diff.ToString() + " seconds");
                }
                break;
            }
            SecondsSinceUpdate[address] = utime;
        }
コード例 #2
0
        // TODO:
        //   How do we want to handle the device status?  There should
        //   be at least 2 devices present (Air & Sky). Do we create
        //   a HS record for each and use that as a place to store the
        //   device specific data?  Or do we just create an internal
        //   list of devivces?
        //
        //   Whatever we do here we should probably do for the hub
        //   as well (treat it as a third device).
        private void DeviceStatus(string json)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            try {
                DeviceObj = serializer.Deserialize <DeviceData>(json);

                // Add event to update this info.
                try {
                    WeatherFlowNS.NS.RaiseDeviceEvent(this, new WFNodeServer.DeviceEventArgs(DeviceObj));
                } catch {
                    WFLogging.Warning("Failed to process device event.");
                }
                WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)DeviceObj.timestamp, DeviceObj.serial_number + "_d", DataType.DEVICE));

                //Console.WriteLine("Serial Number:     " + DeviceObj.serial_number);
                //Console.WriteLine("Device Type:       " + DeviceObj.type);
                //Console.WriteLine("Hub Serial Number: " + DeviceObj.hub_sn);
                //Console.WriteLine("timestamp:         " + DeviceObj.timestamp.ToString());
                //Console.WriteLine("uptime:            " + DeviceObj.uptime.ToString());
                //Console.WriteLine("Voltage:           " + DeviceObj.voltage.ToString());
                //Console.WriteLine("Firmware:          " + DeviceObj.firmware_revision.ToString());
                //Console.WriteLine("RSSI:              " + DeviceObj.rssi.ToString());
                //Console.WriteLine("Sensor status:     " + DeviceObj.sensor_status.ToString());

                if (Sensors.ContainsKey(DeviceObj.serial_number))
                {
                    Sensors[DeviceObj.serial_number] = DeviceObj;
                }
                else
                {
                    Sensors.Add(DeviceObj.serial_number, DeviceObj);
                }
            } catch (Exception ex) {
                WFLogging.Error("Deserialization of device status failed: " + ex.Message);
            }
        }
コード例 #3
0
        private void SkyObservations(string json)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            try {
                SkyObj       = serializer.Deserialize <SkyData>(json);
                SkyObj.valid = true;

                WFNodeServer.SkyEventArgs evnt = new SkyEventArgs(SkyObj);
                evnt.SetDaily = CalcDailyPrecipitation();
                evnt.Raw      = json;

                try {
                    WeatherFlowNS.NS.RaiseSkyEvent(this, evnt);
                } catch (Exception ex) {
                    WFLogging.Warning("Failed to process Sky event. " + ex.Message);
                }
                WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)SkyObj.obs[0][0].GetValueOrDefault(), SkyObj.serial_number, DataType.SKY));
            } catch (Exception ex) {
                WFLogging.Error("Deserialization failed for sky data: " + ex.Message);
                WFLogging.Verbose(json);
                return;
            }
        }
コード例 #4
0
ファイル: wf_websocket.cs プロジェクト: bpaauwe/WFNodeServer
        internal void Start()
        {
            byte[] buf = new byte[512];
            int    len;
            bool   header = false;

            while (Started)
            {
                int retries = 0;

                WFLogging.Warning("Attempt to start already active WebSocket connection " + retries.ToString());
                Thread.Sleep(1000);

                if (retries++ > 10)
                {
                    WFLogging.Error("Giving up after 10 attempts.");
                    return;
                }
            }

            client = new TcpClient(Host, Port);
            if (!client.Connected)
            {
                WFLogging.Error("Client not connected to " + Port);
            }

            WFLogging.Log("Starting communication with websocket server.");
            finished = false;
            Started  = true;

            // Send header
            var seckeybytes = Encoding.UTF8.GetBytes(seckey);

            client.Client.Send(Encoding.ASCII.GetBytes("GET " + Path + " HTTP/1.1\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Host: " + Host + ":" + Port.ToString() + "\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Upgrade: websocket\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Connection: Upgrade\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Pragma: no-cache\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Origin: http://" + Host + "\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Cache-Control: no-cache\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Sec-WebSocket-Key: " + System.Convert.ToBase64String(seckeybytes) + "\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("Sec-WebSocket-Version: 13\r\n"));
            client.Client.Send(Encoding.ASCII.GetBytes("\r\n"));

            WFLogging.Info("    Waiting for handshake");
            Thread.Sleep(100);
            // Receive handshake
            while (!header)
            {
                if (client.Client.Available > 0)
                {
                    len = client.Client.Receive(buf, (client.Client.Available - 1), SocketFlags.None);
                    if (len > 0)
                    {
                        string strbuf = Encoding.ASCII.GetString(buf, 0, len);
                        // Just look for the a websock type response, ignore the rest of the headers
                        if (strbuf.Contains("HTTP/1.1 101"))
                        {
                            header = true;
                        }
                    }
                }
                Thread.Sleep(500);
            }

            receive_thread = new Thread(new ThreadStart(ReceiveLoop));
            receive_thread.IsBackground = true;
            receive_thread.Start();
        }
コード例 #5
0
ファイル: wf_server.cs プロジェクト: bpaauwe/WFNodeServer
        private void ConfigPage(HttpListenerContext context)
        {
            string cfg_page;

            byte[] page;
            byte[] post = new byte[1024];
            Thread do_something;

            //Console.WriteLine("content length = " + context.Request.ContentLength64.ToString());
            if (context.Request.ContentLength64 > 0)
            {
                string[] list;
                string[] pair;
                int      len     = (int)context.Request.ContentLength64;
                bool     initISY = false;
                bool     saveCfg = false;

                context.Request.InputStream.Read(post, 0, len);
                string resp = Encoding.Default.GetString(post);
                resp = resp.Substring(0, len);

                //Console.WriteLine("Response = " + resp);

                cfg_file_status = "";

                if (resp.Contains("stationcfg"))
                {
                    station_form a_form = GetStationInfo(resp);
                    switch (a_form.action)
                    {
                    case "Delete":
                        WFLogging.Info("Delete station " + a_form.station_id.ToString());
                        WeatherFlowNS.NS.DeleteStation(a_form.station_id);
                        saveCfg = true;
                        break;

                    case "++Add++":
                        bool exists = false;
                        WFLogging.Info("Add station " + a_form.station_id.ToString());
                        // Check if station already exists
                        foreach (StationInfo s in WF_Config.WFStationInfo)
                        {
                            if (s.station_id == a_form.station_id)
                            {
                                cfg_file_status = "Station " + a_form.station_id.ToString() + " already exists.";
                                exists          = true;
                                break;
                            }
                        }
                        if (!exists)
                        {
                            saveCfg = AddStation(a_form);
                        }
                        break;

                    case "Update":
                        WFLogging.Info("Update station " + a_form.station_id.ToString());
                        saveCfg = AddStation(a_form);
                        break;

                    default:
                        WFLogging.Warning("Unknown action [" + a_form.action + "]");
                        break;
                    }
                }
                else if (resp.Contains("upload"))
                {
                    // Upload profile files  TODO: Should this be done in a thread?
                    do_something = new Thread(WeatherFlowNS.NS.UpdateProfileFiles);
                    do_something.IsBackground = true;
                    do_something.Start();
                }
                else
                {
                    list = resp.Split('&');
                    foreach (string item in list)
                    {
                        int v = 0;
                        pair    = item.Split('=');
                        pair[1] = HttpUtility.UrlDecode(pair[1]);
                        switch (pair[0])
                        {
                        case "sAddress":
                            if (pair[1] != WF_Config.ISY)
                            {
                                WF_Config.ISY = pair[1];
                                initISY       = true;
                                saveCfg       = true;
                            }
                            break;

                        case "sUsername":
                            if (pair[1] != WF_Config.Username)
                            {
                                WF_Config.Username = pair[1];
                                initISY            = true;
                                saveCfg            = true;
                            }
                            break;

                        case "sPassword":
                            if (pair[1] != WF_Config.Password)
                            {
                                WF_Config.Password = pair[1];
                                initISY            = true;
                                saveCfg            = true;
                            }
                            break;

                        case "sProfile":
                            int.TryParse(pair[1], out v);
                            if (v != WF_Config.Profile)
                            {
                                WF_Config.Profile = v;
                                initISY           = true;
                                saveCfg           = true;
                            }
                            break;

                        case "webPort":
                            int.TryParse(pair[1], out v);
                            if (v != WF_Config.Port)
                            {
                                WF_Config.Port = v;
                                saveCfg        = true;
                            }
                            break;

                        case "sSI":
                            bool imperial = (pair[1] == "1");
                            if (imperial != WF_Config.SI)
                            {
                                WF_Config.SI = (pair[1] == "1");
                                saveCfg      = true;
                            }
                            break;

                        case "sHub":
                            bool hub = (pair[1] == "1");
                            if (hub != WF_Config.Hub)
                            {
                                WF_Config.Hub = (pair[1] == "1");
                                saveCfg       = true;
                            }
                            break;

                        case "sDevice":
                            bool device = (pair[1] == "1");
                            if (device != WF_Config.Device)
                            {
                                WF_Config.Device = (pair[1] == "1");
                                saveCfg          = true;
                            }
                            break;

                        case "sUnits":
                            int.TryParse(pair[1], out v);
                            if (v != WF_Config.Units)
                            {
                                WF_Config.Units = v;
                                saveCfg         = true;
                            }
                            break;

                        case "sLogLevel":
                            int.TryParse(pair[1], out v);
                            if (v != WF_Config.LogLevel)
                            {
                                WF_Config.LogLevel = v;
                                WFLogging.Level    = (LOG_LEVELS)v;
                                saveCfg            = true;
                            }
                            break;

                        case "serverctl":
                            if (pair[1].Contains("Restart"))
                            {
                                WeatherFlowNS.NS.udp_client.Start();
                                WeatherFlowNS.NS.heartbeat.Start();
                                cfg_file_status = "Server Started";
                                Thread.Sleep(400);
                            }
                            else if (pair[1].Contains("Pause"))
                            {
                                WeatherFlowNS.NS.heartbeat.Stop();
                                WeatherFlowNS.NS.udp_client.Stop();
                                cfg_file_status = "Server Paused";
                            }
                            break;

                        case "websocket":
                            if (pair[1].Contains("Start"))
                            {
                                try {
                                    WeatherFlowNS.NS.StartWebSocket();
                                } catch (Exception ex) {
                                    WFLogging.Error("Starting websocket client failed: " + ex.Message);
                                }
                                cfg_file_status = "Websocket Client Started";
                                Thread.Sleep(400);
                            }
                            else if (pair[1].Contains("Stop"))
                            {
                                WeatherFlowNS.NS.wsi.Stop();
                                cfg_file_status = "Websocket Client Stopped";
                                Thread.Sleep(800);
                            }
                            break;

                        default:
                            break;
                        }
                    }
                }

                if (saveCfg)
                {
                    cfg_file_status += WeatherFlowNS.SaveConfiguration();
                }
                if (initISY)
                {
                    WeatherFlowNS.NS.InitializeISY();
                }
            }

            try {
                cfg_page = MakeConfigPage();
            } catch (Exception ex) {
                WFLogging.Error("Failed to make configuration web page.");
                WFLogging.Error(ex.Message);
                context.Response.Close();
                return;
            }
            // How can we substitute values into the page?  May need to dynamically
            // generate the page instead of storing it as a resource.  That would
            // be a bit of a pain.

            page = ASCIIEncoding.ASCII.GetBytes(cfg_page);

            context.Response.ContentType     = "text/html";
            context.Response.ContentLength64 = page.Length;
            context.Response.AddHeader("Date", DateTime.Now.ToString("r"));
            context.Response.StatusCode = (int)HttpStatusCode.OK;
            context.Response.OutputStream.Write(page, 0, page.Length);
            context.Response.OutputStream.Flush();
            context.Response.OutputStream.Close();
            context.Response.Close();
        }
コード例 #6
0
        private void AirObservations(string json)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            // obs[0][0] = time (seconds)
            // obs[0][1] = station pressure (MB)
            // obs[0][2] = air temp (c)
            // obs[0][3] = humidity (%)

            // obs[0][4] = lightning count
            // obs[0][5] = avg lightning dist (km)
            // obs[0][6] = battery
            // obs[0][7] = interval (minutes)
            try {
                double elevation = 0;

                AirObj       = serializer.Deserialize <AirData>(json);
                AirObj.valid = true;

                // Look up elevation
                StationInfo si = wf_station.FindStationAir(AirObj.serial_number);
                if (si != null)
                {
                    elevation = si.elevation;
                }

                // Do we just want to raise an event with the data object?
                AirEventArgs evnt = new AirEventArgs(AirObj);
                evnt.SetDewpoint     = 0;
                evnt.SetApparentTemp = 0;
                evnt.SetTrend        = 1;
                evnt.SetSeaLevel     = SeaLevelPressure(AirObj.obs[0][(int)AirIndex.PRESSURE].GetValueOrDefault(), elevation);
                evnt.Raw             = json;
                if (SkyObj.valid)
                {
                    try {
                        evnt.SetDewpoint     = CalcDewPoint();
                        evnt.SetApparentTemp = FeelsLike(AirObj.obs[0][(int)AirIndex.TEMPURATURE].GetValueOrDefault(),
                                                         AirObj.obs[0][(int)AirIndex.HUMIDITY].GetValueOrDefault(),
                                                         SkyObj.obs[0][(int)SkyIndex.WIND_SPEED].GetValueOrDefault());
                        // Trend is -1, 0, 1 while event wants 0, 1, 2
                        evnt.SetTrend = PressureTrend() + 1;
                        // Heat index & Windchill ??
                    } catch {
                    }
                }
                else
                {
                }

                try {
                    WeatherFlowNS.NS.RaiseAirEvent(this, evnt);
                } catch (Exception ex) {
                    WFLogging.Warning("Failed to process Air event. " + ex.Message);
                }
                WeatherFlowNS.NS.RaiseUpdateEvent(this, new UpdateEventArgs((int)AirObj.obs[0][0].GetValueOrDefault(), AirObj.serial_number, DataType.AIR));
            } catch (Exception ex) {
                WFLogging.Error("Deserialization failed for air data: " + ex.Message);
                WFLogging.Verbose(json);
            }
        }