Слушает telemetry.new_reading (ручной ack/nack, реквизишн только при транспортных ошибках gRPC), кэширует активные automation_rules в памяти с периодическим обновлением из PostgreSQL (JOIN с devices — резолвит внутренние ID в external_id, которым оперируют MQTT/Redis/gRPC). Условия правил (>,<,>=,<=,=,!=) оцениваются обобщённо, без привязки к конкретным типам устройств. При срабатывании вызывает device-control-service по gRPC и публикует automation.rule_triggered в RabbitMQ. Проверено сквозным тестом через docker compose на полном пайплайне: mosquitto_pub → ingest-service (ClickHouse + telemetry.new_reading) → rule-engine-service (совпадение правила) → device-control-service (gRPC → Redis desired_state + MQTT-команда) → automation.rule_triggered. Показание ниже порога проверено отдельно — правило корректно не срабатывает.
42 lines
1.3 KiB
Go
42 lines
1.3 KiB
Go
// Package rules holds the generic automation-rule model and condition
|
|
// evaluation logic. Nothing here knows about growboxes, lights, or pumps —
|
|
// only sensor_type/operator/value, exactly as stored in automation_rules.
|
|
package rules
|
|
|
|
import "fmt"
|
|
|
|
// Rule mirrors one row of automation_rules, joined against devices so the
|
|
// device IDs are the external identifiers used by MQTT/Redis/gRPC (not
|
|
// PostgreSQL's internal bigserial IDs).
|
|
type Rule struct {
|
|
ID int64
|
|
ZoneID int64
|
|
SourceDeviceID string // condition_source_device_id, resolved to devices.external_id
|
|
ConditionSensorType string
|
|
ConditionOperator string
|
|
ConditionValue float64
|
|
TargetDeviceID string // target_device_id, resolved to devices.external_id
|
|
ActionType string
|
|
ActionParams map[string]any
|
|
}
|
|
|
|
// Evaluate reports whether value satisfies the rule's condition.
|
|
func Evaluate(operator string, value, threshold float64) (bool, error) {
|
|
switch operator {
|
|
case ">":
|
|
return value > threshold, nil
|
|
case "<":
|
|
return value < threshold, nil
|
|
case ">=":
|
|
return value >= threshold, nil
|
|
case "<=":
|
|
return value <= threshold, nil
|
|
case "=":
|
|
return value == threshold, nil
|
|
case "!=":
|
|
return value != threshold, nil
|
|
default:
|
|
return false, fmt.Errorf("unknown condition operator %q", operator)
|
|
}
|
|
}
|