public void Handle(string json)
        {
            Console.WriteLine("MOTION event handler invoked ...");
            try
            {
                var eventObj = JsonConvert.DeserializeObject <Event>(json);
                Console.WriteLine("[MotionEventHandler] Handling eventObj: " + eventObj);

                if (eventObj.category.ToLower() == "user_environment")
                {
                    // if we are dealing with a presence sensor
                    if (eventObj.content.name == "presence")
                    {
                        // see if it is a sensor activation
                        if (eventObj.content.val["alarm_motion"] != null && (bool)eventObj.content.val["alarm_motion"])
                        {
                            // retrieve the gateway and sensor URI from the source annotations
                            var gatewayURIPath = (string)eventObj.annotations.source["gateway"];
                            var deviceURIPath  = (string)eventObj.annotations.source["sensor"];

                            // make a call to the store API to get the user from the gateway
                            var userURIPath = storeAPI.GetUserOfGateway(gatewayURIPath);

                            if (userURIPath != null)
                            {
                                int userID = GetIdFromURI(userURIPath);
                                Tuple <string, string> userLocales = storeAPI.GetUserLocale(userURIPath, userID);

                                if (userLocales != null)
                                {
                                    // retrieve timestamp from annotations
                                    long timestamp = eventObj.annotations.timestamp;

                                    // get localized datetime
                                    TimeZoneInfo localTz     = TimeZoneInfo.FindSystemTimeZoneById(userLocales.Item2);
                                    DateTime     dtime       = UnixTimeStampToDateTime(timestamp, localTz);
                                    DateTime     currentTime = UnixTimeStampToDateTime((long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds, localTz);

                                    // get morning limits
                                    Tuple <DateTime, DateTime> morningLimits = getMorningLimits(localTz);

                                    // check if current dtime is within limits
                                    if (dtime >= morningLimits.Item1 && currentTime >= morningLimits.Item1 && dtime <= morningLimits.Item2 && currentTime <= morningLimits.Item2)
                                    //if (dtime >= morningLimits.Item1 && dtime <= morningLimits.Item2)
                                    {
                                        if (lastActivationMap.ContainsKey(userURIPath))
                                        {
                                            long     lastTs = lastActivationMap[userURIPath];
                                            DateTime lastDt = UnixTimeStampToDateTime(lastTs, localTz);

                                            // if the lastDt is outside of the morning limits
                                            if (lastDt < morningLimits.Item1)
                                            {
                                                Console.WriteLine("[MotionEventHandler] Identified first activation of motion sensor in morning at : " + dtime.ToString());
                                                SendBPMeasurementNotification(userURIPath);
                                            }

                                            lastActivationMap[userURIPath] = timestamp;
                                        }
                                        else
                                        {
                                            // if this is the first activation ever within morning limits
                                            Console.WriteLine("[MotionEventHandler] First ever activation of motion sensor in morning at : " + dtime.ToString());
                                            SendBPMeasurementNotification(userURIPath);

                                            lastActivationMap[userURIPath] = timestamp;
                                        }
                                    }
                                    else
                                    {
                                        // just mark as latest activation
                                        Console.WriteLine("[MotionEventHandler] Motion event not within morning limits " + dtime.ToString());
                                        lastActivationMap[userURIPath] = timestamp;
                                    }
                                }
                                else
                                {
                                    Console.WriteLine("[MotionEventHandler] Insufficient locales information in enduser profile endpoint for user: "******"[MotionEventHandler] Skipping motion event handling since no user can be retrieved for gateway: " + gatewayURIPath);
                            }
                        }
                        else
                        {
                            Console.WriteLine("[MotionEventHandler] The motion sensor has not been triggered: " + eventObj.content.val["alarm_motion"]);
                        }
                    }
                }
            }
            catch (JsonException ex)
            {
                Console.WriteLine(ex);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
Example #2
0
        public void Handle(string json)
        {
            Console.WriteLine("Measurement handler invoked " + DateTime.UtcNow);

            var obj = JsonConvert.DeserializeObject <Measurement>(json, settings);

            string END_USER_URI = obj.user;
            int    userId       = storeAPI.GetIdFromURI(obj.user);

            Tuple <string, string> userLocales = storeAPI.GetUserLocale(END_USER_URI, userId);
            var LANG  = userLocales.Item1;
            var tZone = userLocales.Item2;

            //var LANG = storeAPI.GetLang(obj.user);

            if (obj.measurement_type == "weight")
            {
                var weightValInfo = (WeightValueInfo)obj.value_info;

                var val = weightValInfo.Value;
                var kg  = storeAPI.GetLatestWeightMeasurement(userId);

                var trend = "normal";
                obj.ok = true;

                if (kg != 0)
                {
                    if (Math.Abs(val - kg) > 2)
                    {
                        trend  = val > kg ? "up" : "down";
                        obj.ok = false;
                    }
                }

                storeAPI.PushMeasurement(JsonConvert.SerializeObject(obj));

                if (trend == "down" || trend == "up")
                {
                    var category = trend == "up" ? Loc.WEIGHT_INC : Loc.WEIGHT_DEC;

                    var endUserMsg   = string.Format(Loc.Get(LANG, Loc.MSG, category, Loc.USR), Math.Floor(Math.Abs(val - kg)));
                    var caregiverMsg = string.Format(Loc.Get(LANG, Loc.MSG, category, Loc.CAREGVR), Math.Floor(Math.Abs(val - kg)));

                    InformUser(END_USER_URI, "weight", "medium", endUserMsg, Loc.Get(LANG, Loc.DES, category, Loc.USR));
                    InformCaregivers(END_USER_URI, "weight", "medium", caregiverMsg, Loc.Get(LANG, Loc.DES, category, Loc.CAREGVR));
                }
            }
            else if (obj.measurement_type == "pulse")
            {
                var pulseValInfo = (PulseValueInfo)obj.value_info;
                var val          = pulseValInfo.Value;

                var min     = 50;
                var midLow  = 60;
                var midHigh = 100;
                var max     = 120;

                if (val < min || val > max)
                {
                    obj.ok = false;
                }
                else
                {
                    obj.ok = true;
                }


                storeAPI.PushMeasurement(JsonConvert.SerializeObject(obj));

                TimeZoneInfo localTz                = TimeZoneInfo.FindSystemTimeZoneById(tZone);
                DateTime     pulseDateTime          = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(obj.timestamp);
                DateTime     localizedPulseDateTime = UnixTimeStampToDateTime(obj.timestamp, localTz);

                if (pulseDateTime.AddHours(1) > DateTime.UtcNow && localizedPulseDateTime.Hour >= 6)
                {
                    AnalyzePulseValue(val, min, midLow, midHigh, max, END_USER_URI);
                }

                /*
                 * if (val < min || val > max)
                 * {
                 *                      obj.ok = false;
                 *
                 *
                 *                      // For the AAL Forum we will analyse each pulse measurement individually because we do not expect them to arrive very often
                 *  // In any case, we will need a mechanism to switch between an individual and an aggregated analysis, based on context
                 *  // (e.g. how frequently do the measurements arrive and what is their source)
                 *
                 *  if(storeAPI.AreLastNHeartRateCritical(3, min, max))
                 *  {
                 *      var anEvent = new RMQ.INS.Event() { category = "HEART_RATE", content = new RMQ.INS.Content() { num_value = val } };
                 *      insertionAPI.InsertEvent( JsonConvert.SerializeObject(anEvent));
                 *  }
                 *
                 *                  //storeAPI.PushJournalEntry("Pulse is abnormal", "Pulse is abnormal", "pulse");
                 *              }
                 * else
                 * {
                 *  obj.ok = true;
                 *              }
                 */
            }
            else if (obj.measurement_type == "blood_pressure")
            {
                // TODO: for now we are treating the pulse values from blood_pressure measurements (if they contain one) in the same
                // way in which we would handle pulse measurements from the FitBit. This is mostly for demo purposes and will change in the future.

                // First, just save the blood_pressure measurement in the CAMI Store, marking it as ok, because we perform no analysis on BP values
                obj.ok = true;
                storeAPI.PushMeasurement(JsonConvert.SerializeObject(obj));

                // Then perform analysis on Pulse value, if there is any

                var bpValInfo = (BloodPressureValueInfo)obj.value_info;
                var val       = bpValInfo.pulse;

                // if it has pulse information
                if (val != 0)
                {
                    var min     = 50;
                    var midLow  = 60;
                    var midHigh = 100;
                    var max     = 120;

                    // create a new measurement object of type Pulse, copying over meta data from the BP obj
                    var pulseObj = new Measurement();
                    pulseObj.measurement_type = "pulse";
                    pulseObj.unit_type        = "bpm";

                    pulseObj.timestamp  = obj.timestamp;
                    pulseObj.user       = obj.user;
                    pulseObj.device     = obj.device;
                    pulseObj.gateway_id = obj.gateway_id;

                    var pulseValInfo = new PulseValueInfo();
                    pulseValInfo.Value  = val;
                    pulseObj.value_info = pulseValInfo;

                    if (val < min || val > max)
                    {
                        pulseObj.ok = false;
                    }
                    else
                    {
                        pulseObj.ok = true;
                    }


                    // first store the measurement in the CAMI Store
                    storeAPI.PushMeasurement(JsonConvert.SerializeObject(pulseObj));

                    // TODO: currently we know that notification are handled client side only for the CamiDemo user (id = 2), so if we are not
                    // handling data for that user, do not send alerts

                    AnalyzePulseValue(val, min, midLow, midHigh, max, END_USER_URI);
                }
            }


            else if (obj.measurement_type == "steps")
            {
                Console.WriteLine("Steps invoked!");

                obj.ok = true;
                storeAPI.PushMeasurement(JsonConvert.SerializeObject(obj));



                // start the step count timer for this user if not already done so
                StartStepsTimer(obj.user);
            }
            else
            {
                // for measurements for which there is no analysis, just mark the measurement as ok and insert it in the CAMI Store
                obj.ok = true;
                storeAPI.PushMeasurement(JsonConvert.SerializeObject(obj));
            }
        }