removed kicad-libs and teenstep after moving to github
[svn42.git] / go / r3-eventbroker_zmq / presence.go
index 154c6d2..8ea2693 100644 (file)
@@ -3,70 +3,88 @@
 package main
 
 import (
-    "time"
-    //~ "./brain"
-    pubsub "github.com/tuxychandru/pubsub"
-    )
+       "time"
+       //~ "./brain"
+       pubsub "github.com/tuxychandru/pubsub"
+       r3events "svn.spreadspace.org/realraum/go.svn/r3events"
+)
 
-type PresenceUpdate struct {
-    Present bool
-    Ts int64
-}
-
-type doorstate struct {
-    locked bool
-    shut bool
-}
+func MetaEventRoutine_Presence(ps *pubsub.PubSub, movement_timeout, button_timeout int64) {
+       var last_door_cmd *r3events.DoorCommandEvent
+       var last_presence bool
+       var last_event_indicating_presence, last_frontlock_use, last_manual_lockhandling int64
+       var front_locked, front_shut, back_shut bool = true, true, true
 
-func MetaEventRoutine_Presence(ps *pubsub.PubSub) {
-    //~ var last_door_cmd *DoorCommandEvent
-    var last_presence bool
-    var last_movement, last_buttonpress int64
-    doorstatemap := make(map[int]doorstate,1)
+       events_chan := ps.Sub("door", "doorcmd", "buttons", "movement")
+       defer ps.Unsub(events_chan, "door", "doorcmd", "buttons", "movement")
 
-    events_chan := ps.Sub("door", "doorcmd", "buttons", "movement")
+       for event := range events_chan {
+               Debug_.Printf("Presence prior: %t : %T %+v", last_presence, event, event)
+               new_presence := last_presence
+               ts := time.Now().Unix()
+               evnt_type := r3events.NameOfStruct(event)
+               switch evnt := event.(type) {
+               case r3events.SomethingReallyIsMoving:
+                       if evnt.Movement {
+                               //ignore movements that happened just after locking door
+                               if (evnt.Ts - last_event_indicating_presence) > movement_timeout {
+                                       new_presence = true
+                               }
+                               last_event_indicating_presence = evnt.Ts
+                       } else {
+                               if last_presence {
+                                       Syslog_.Printf("Presence: Mhh, SomethingReallyIsMoving{%+v} received but presence still true. Quite still a bunch we have here.", evnt)
+                               }
+                               if front_locked && front_shut && back_shut && evnt.Confidence >= 90 && last_event_indicating_presence > 1800 && (last_door_cmd == nil || (last_door_cmd.Using != "Button" && last_door_cmd.Ts >= last_manual_lockhandling)) {
+                                       new_presence = false
+                               }
+                       }
+               case r3events.BoreDoomButtonPressEvent:
+                       new_presence = true
+                       last_event_indicating_presence = evnt.Ts
+               case r3events.DoorCommandEvent:
+                       last_door_cmd = &evnt
+               case r3events.DoorManualMovementEvent:
+                       last_manual_lockhandling = evnt.Ts
+                       last_event_indicating_presence = evnt.Ts
+               case r3events.DoorLockUpdate:
+                       front_locked = evnt.Locked
+                       last_frontlock_use = evnt.Ts
+                       last_event_indicating_presence = evnt.Ts
+               case r3events.DoorAjarUpdate:
+                       if front_shut == false && evnt.Shut && front_locked && evnt.Ts-last_frontlock_use > 2 {
+                               Syslog_.Print("Presence: ignoring frontdoor ajar event, since obviously someone is fooling around with the microswitch while the door is still open")
+                       } else {
+                               front_shut = evnt.Shut
+                       }
+                       last_event_indicating_presence = evnt.Ts
+               case r3events.BackdoorAjarUpdate:
+                       back_shut = evnt.Shut
+                       last_event_indicating_presence = evnt.Ts
+               }
 
-    for event := range(events_chan) {
-        new_presence := last_presence
-        ts := time.Now().Unix()
-        switch evnt := event.(type) {
-            case SomethingReallyIsMoving:
-                if evnt.Movement {
-                    last_movement = evnt.Ts
-                } else {
-                    last_movement = 0
-                }
-            case ButtonPressUpdate:
-                last_buttonpress = evnt.Ts
-                new_presence = true
-            //~ case DoorCommandEvent:
-                //~ last_door_cmd = &evnt
-            case DoorLockUpdate:
-                doorstatemap[evnt.DoorID]=doorstate{locked:evnt.Locked, shut:doorstatemap[evnt.DoorID].shut}
-            case DoorAjarUpdate:
-                doorstatemap[evnt.DoorID]=doorstate{locked:doorstatemap[evnt.DoorID].locked, shut:evnt.Shut}
-        }
+               any_door_unlocked := (front_locked == false)
+               any_door_ajar := !(front_shut && back_shut)
 
-        any_door_unlocked := false
-        any_door_ajar := false
-        for _, ds := range(doorstatemap) {
-            if ds.locked == false {any_door_unlocked = true }
-            if ds.shut == false {any_door_ajar = true }
-        }
-
-        if new_presence != last_presence {
-            //... skip state check .. we had a definite presence event
-        } else if any_door_unlocked || any_door_ajar {
-            new_presence = true
-        } else if last_movement != 0 || ts - last_buttonpress < 200 {
-            new_presence = true
-        } else {
-            new_presence = false
-        }
-
-        if new_presence != last_presence {
-            last_presence = new_presence
-            ps.Pub(PresenceUpdate{new_presence, ts} , "presence")
-        }
-    }
-}
\ No newline at end of file
+               if new_presence != last_presence {
+                       //... skip state check .. we had a definite presence event
+               } else if any_door_unlocked || any_door_ajar {
+                       new_presence = true
+               } else if last_door_cmd != nil && (last_door_cmd.Using == "Button" || last_door_cmd.Ts < last_manual_lockhandling) {
+                       // if last_door_cmd is set then: if either door was closed using Button or if time of manual lock movement is greater (newer) than timestamp of last_door_cmd
+                       new_presence = true
+               } else if evnt_type == "DoorCommandEvent" {
+                       //don't set presence to false for just a door command, wait until we receive a LockUpdate
+                       //(fixes "door manually locked -> door opened with card from outside -> nobody present status sent since door is locked and we havent received door unloked event yet"-problem)
+                       continue
+               } else {
+                       new_presence = false
+               }
+               //~ Debug_.Printf("Presence: new: %s , last:%s", new_presence, last_presence)
+               if new_presence != last_presence {
+                       last_presence = new_presence
+                       ps.Pub(r3events.PresenceUpdate{new_presence, ts}, "presence")
+                       Syslog_.Printf("Presence: %t", new_presence)
+               }
+       }
+}