@@ -29,7 +29,9 @@ public async Task<bool> SaveNotificationSettingAsync(NotificationSetting setting
2929
3030 public async Task<List<NotificationRule>> GetNotificationRulesAsync()
3131 {
32- var rules = await _dbService.Db.Queryable<NotificationRule>().ToListAsync();
32+ var rules = await _dbService.Db.Queryable<NotificationRule>()
33+ .OrderBy(r => r.SortOrder)
34+ .ToListAsync();
3335 if (rules.Any())
3436 {
3537 var ruleIds = rules.Select(r => r.Id).ToList();
@@ -61,12 +63,14 @@ public async Task<bool> SaveNotificationRuleAsync(NotificationRule rule)
6163 // Explicitly handle Insert vs. Update for the rule for more reliability
6264 if (rule.Id == 0)
6365 {
64- // It's a new rule, insert it and get the new ID
66+ // New rule: assign SortOrder as max existing + 1
67+ var maxSort = await _dbService.Db.Queryable<NotificationRule>().MaxAsync<int>(r => r.SortOrder);
68+ rule.SortOrder = maxSort + 1;
6569 rule.Id = await _dbService.Db.Insertable(rule).ExecuteReturnIdentityAsync();
6670 }
6771 else
6872 {
69- // It's an existing rule, update it
73+ // Existing rule: update
7074 await _dbService.Db.Updateable(rule).ExecuteCommandAsync();
7175 }
7276
@@ -125,37 +129,62 @@ public async Task CheckAndSendNotificationsAsync(IEnumerable<SensorData> sensorR
125129
126130 foreach (var rule in rules.Where(r => r.IsEnabled && r.Conditions.Any()))
127131 {
128- var allConditionsMet = true;
129- var conditionsSummary = new StringBuilder();
130-
131- foreach (var condition in rule.Conditions)
132+ var shouldTrigger = EvaluateRuleConditions(rule.Conditions, sensorReadingsList);
133+
134+ if (shouldTrigger.IsMet)
132135 {
133- var sensorReading = sensorReadingsList.FirstOrDefault(s =>
134- string.Equals(s.SensorName, condition.SensorName, StringComparison.OrdinalIgnoreCase));
136+ await HandleTriggeredRule(rule, settings, shouldTrigger.Summary);
137+ }
138+ }
139+ }
135140
136- if (sensorReading == null)
137- {
138- // If a sensor in a condition is not found in the latest readings, the condition cannot be met.
139- allConditionsMet = false;
140- break;
141- }
141+ private (bool IsMet, string Summary) EvaluateRuleConditions(List<NotificationCondition> conditions, List<SensorData> sensorReadings)
142+ {
143+ if (!conditions.Any()) return (false, "");
142144
143- var conditionMetThisCycle = IsConditionMet(sensorReading.Reading, condition.Threshold, condition.Operator);
145+ var conditionsSummary = new StringBuilder();
146+ var results = new List<bool>();
144147
145- if (!conditionMetThisCycle)
146- {
147- allConditionsMet = false;
148- break;
149- }
148+ // Evaluate each condition
149+ foreach (var condition in conditions)
150+ {
151+ var sensorReading = sensorReadings.FirstOrDefault(s =>
152+ string.Equals(s.SensorName, condition.SensorName, StringComparison.OrdinalIgnoreCase));
150153
154+ if (sensorReading == null)
155+ {
156+ // If sensor not found, condition is false
157+ results.Add(false);
158+ continue;
159+ }
160+
161+ var conditionMet = IsConditionMet(sensorReading.Reading, condition.Threshold, condition.Operator);
162+ results.Add(conditionMet);
163+
164+ if (conditionMet)
165+ {
151166 conditionsSummary.Append($"{sensorReading.SensorName} was {sensorReading.Reading:F1}{sensorReading.Unit}; ");
152167 }
168+ }
169+
170+ // Apply And/Or logic
171+ var finalResult = results[0]; // Start with first condition result
153172
154- if (allConditionsMet)
173+ for (int i = 1; i < conditions.Count; i++)
174+ {
175+ var connector = conditions[i].Connector;
176+
177+ if (connector == ConditionLogicalOperator.And)
155178 {
156- await HandleTriggeredRule(rule, settings, conditionsSummary.ToString().TrimEnd(' ', ';'));
179+ finalResult = finalResult && results[i];
180+ }
181+ else if (connector == ConditionLogicalOperator.Or)
182+ {
183+ finalResult = finalResult || results[i];
157184 }
158185 }
186+
187+ return (finalResult, conditionsSummary.ToString().TrimEnd(' ', ';'));
159188 }
160189
161190 private async Task HandleTriggeredRule(NotificationRule rule, NotificationSetting settings, string conditionsSummary)
@@ -370,4 +399,4 @@ private async Task<bool> SendWeComBotAsync(string key, string message)
370399 return false;
371400 }
372401 }
373- }
402+ }
0 commit comments