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); } }
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)); } }