| 
     1 const hap = require("hap-nodejs"); | 
         | 
     2 const pysh = require("python-shell"); | 
         | 
     3   | 
         | 
     4 const Accessory = hap.Accessory;  | 
         | 
     5 const Characteristic = hap.Characteristic;  | 
         | 
     6 const CharacteristicEventTypes = hap.CharacteristicEventTypes;  | 
         | 
     7 const AccessoryEventTypes = hap.AccessoryEventTypes;  | 
         | 
     8 const Service = hap.Service;  | 
         | 
     9 const uuid = hap.uuid;  | 
         | 
    10   | 
         | 
    11 const accessoryUuid = hap.uuid.generate("hap.accessories.doorbell-lock"); | 
         | 
    12 const accessory = new Accessory("Doorbell and Lock", accessoryUuid); | 
         | 
    13   | 
         | 
    14 const doorbellService = new Service.Doorbell("Doorbell"); | 
         | 
    15 const lockService = new Service.LockMechanism("Lock"); | 
         | 
    16   | 
         | 
    17 const lockTargetStateCharacteristic = lockService.getCharacteristic(Characteristic.LockTargetState);  | 
         | 
    18 const lockCurrentStateCharacteristic = lockService.getCharacteristic(Characteristic.LockCurrentState);  | 
         | 
    19   | 
         | 
    20 const doorbellSwitchCharacteristic = doorbellService.getCharacteristic(Characteristic.ProgrammableSwitchEvent);  | 
         | 
    21   | 
         | 
    22 function Door() { | 
         | 
    23     this.lockTimeout = 10000; // milliseconds - 10 sec  | 
         | 
    24   | 
         | 
    25     this.pyshell = new pysh.PythonShell("doord.py", { | 
         | 
    26         mode: "text",  | 
         | 
    27         pythonPath: "/usr/bin/python3",  | 
         | 
    28         pythonOptions: ["-u"],  | 
         | 
    29         scriptPath: "python/"  | 
         | 
    30     });  | 
         | 
    31   | 
         | 
    32     this.lock = () => { | 
         | 
    33         console.log("locking door"); | 
         | 
    34         this.pyshell.send("lock"); | 
         | 
    35     };  | 
         | 
    36   | 
         | 
    37     this.unlock = () => { | 
         | 
    38         console.log("unlocking door"); | 
         | 
    39         this.pyshell.send("unlock"); | 
         | 
    40     };  | 
         | 
    41   | 
         | 
    42     this.identify = () => { console.log("identify door"); }; | 
         | 
    43   | 
         | 
    44     this.listenDoorbell = (doorbellOnCallback, doorbellOffCallback) => { | 
         | 
    45         this.pyshell.on("message", (message) => { | 
         | 
    46             console.log(message);  | 
         | 
    47             switch(message) { | 
         | 
    48             case "doorbell on":  | 
         | 
    49                 doorbellOnCallback();  | 
         | 
    50                 break;  | 
         | 
    51             case "doorbell off":  | 
         | 
    52                 doorbellOffCallback();  | 
         | 
    53                 break;  | 
         | 
    54             }  | 
         | 
    55         });  | 
         | 
    56     };  | 
         | 
    57 }  | 
         | 
    58   | 
         | 
    59 const door = new Door();  | 
         | 
    60   | 
         | 
    61 function setDoorTargetState(value) { | 
         | 
    62     switch(value) { | 
         | 
    63     case Characteristic.LockTargetState.UNSECURED:  | 
         | 
    64         unlockDoor();  | 
         | 
    65         break;  | 
         | 
    66     case Characteristic.LockTargetState.SECURED:  | 
         | 
    67         lockDoor();  | 
         | 
    68         break;  | 
         | 
    69     }  | 
         | 
    70 }  | 
         | 
    71   | 
         | 
    72 function unlockDoor() { | 
         | 
    73     door.unlock();  | 
         | 
    74     lockCurrentStateCharacteristic.setValue(Characteristic.LockCurrentState.UNSECURED);  | 
         | 
    75     scheduleUnlockTimeout();  | 
         | 
    76 }  | 
         | 
    77   | 
         | 
    78 function lockDoor() { | 
         | 
    79     door.lock();  | 
         | 
    80     lockCurrentStateCharacteristic.setValue(Characteristic.LockCurrentState.SECURED);  | 
         | 
    81 }  | 
         | 
    82   | 
         | 
    83 function scheduleUnlockTimeout() { | 
         | 
    84     setTimeout(() => { | 
         | 
    85         console.log("unlock timeout door"); | 
         | 
    86         lockTargetStateCharacteristic.setValue(Characteristic.LockTargetState.SECURED);  | 
         | 
    87     }, door.lockTimeout);  | 
         | 
    88 }  | 
         | 
    89   | 
         | 
    90 door.listenDoorbell(  | 
         | 
    91     () => { | 
         | 
    92         doorbellSwitchCharacteristic.setValue(Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS);  | 
         | 
    93     },  | 
         | 
    94     () => {} | 
         | 
    95 );  | 
         | 
    96   | 
         | 
    97 // set initial state  | 
         | 
    98 lockTargetStateCharacteristic.setValue(Characteristic.LockTargetState.SECURED);  | 
         | 
    99 lockCurrentStateCharacteristic.setValue(Characteristic.LockCurrentState.SECURED);  | 
         | 
   100 lockTargetStateCharacteristic.on(CharacteristicEventTypes.SET, (value, callback) => { | 
         | 
   101     setDoorTargetState(value);  | 
         | 
   102     callback();  | 
         | 
   103 });  | 
         | 
   104   | 
         | 
   105 accessory.on(AccessoryEventTypes.IDENTIFY, (paired, callback) => { | 
         | 
   106     door.identify();  | 
         | 
   107     callback();  | 
         | 
   108 });  | 
         | 
   109   | 
         | 
   110 accessory.addService(doorbellService);  | 
         | 
   111 accessory.addService(lockService);  | 
         | 
   112   | 
         | 
   113 accessory.getService(Service.AccessoryInformation)  | 
         | 
   114     .setCharacteristic(Characteristic.Manufacturer, "Raspberry Pi")  | 
         | 
   115     .setCharacteristic(Characteristic.Model, "Zero W")  | 
         | 
   116     .setCharacteristic(Characteristic.SerialNumber, "A1S2NASF88EW");  | 
         | 
   117   | 
         | 
   118 accessory.publish({ | 
         | 
   119   username: "C1:5D:3A:EA:54:AB",  | 
         | 
   120   pincode: "031-45-154",  | 
         | 
   121   category: hap.Categories.DOOR_LOCK  | 
         | 
   122 });  | 
         | 
   123   | 
         | 
   124 console.log("Accessory initialized"); |