Presence detection with Netamo Welcome

This rule is used to set a switch item (ON / OFF) following the person presence last seen channel from Netatmo Welcome camera.

The destination item (switch) is part of the Generic Presence Detection, as a PersonSensor (Thanks Rich Koshak).

Requirements:
- Netatmo Welcome camera
- One or more Switches determines whether someone is present
- A group with all persons last seen channel (gNetatmoPresence)
- The label (of the person last seen channel) should be the uid of the switch item.

The rule:

The rule is running each 2 min via cron.

The script:

For each channel from the group, if current time is between Ā«last seenĀ» timestamp and Ā«last seenĀ» timestamp + 15 min, the person is considered to be at home. The switch is set to ā€œONā€.

All Ā«log infoĀ» can be removed (it is only for debugging!)

1 Like

This looks like a good candidate for a rule template. See How to write a rule template. Youā€™ve figured out the hard part so all thatā€™s left is a minor formatting change and adding some properties (e.g. set the Items and the timeout based on a property instead of hard codeing.

Even for Blockly, the best way to share a rule, if you donā€™t do a rule template, is to click on the ā€œCodeā€ tab and paste the text you see there into the post using code fences.

```
code goes here
```

Definitely post a screen shot of the blocks too, but with the actual code the rule can be copied and pasted instead of recreated from scratch. A rule template is even better since the user can install it like a binding and configure it like a Thing.

Thanks Rich. I will do so, but I will need time to understand how toā€¦ :slight_smile:
Waiting:

var X, msg, rawLabel, lastSeen;

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);

var dtf = Java.type("java.time.format.DateTimeFormatter");

var zdt = Java.type("java.time.ZonedDateTime");

/* Try to detect the format based on its length */
function getZonedDateTime(datetime) {
  datetime = String(datetime).replace('T', ' ')
  switch (datetime.length) {
    case 10: return zdt.parse(datetime + ' 00:00:00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
    case 16: return zdt.parse(datetime + ':00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
    case 19: return zdt.parse(datetime + '+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
    case 25: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
    case 23: return zdt.parse(datetime + ' +00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSS z'));
    case 26: return zdt.parse(datetime + ' +00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSSS z'));
    case 29: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSz'));
    case 32: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSSSSz'));
    case 28: return zdt.parse(datetime.slice(0,26) + ':' + datetime.slice(26,28), dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSz'));
    default: return zdt.parse(datetime);
  }
}

function createZonedDateTime(year, month, day, hour, minute, second, nano, offsetString, timezoneString) {
  stringToParse = '' + year;
  stringToParse += '-' + ('0' + month).slice(-2);
  stringToParse += '-' + ('0' + day).slice(-2);
  stringToParse += 'T' + ('0' + hour).slice(-2);
  stringToParse += ':' + ('0' + minute).slice(-2);
  stringToParse += ':' + ('0' + second).slice(-2);
  stringToParse += '.' + nano + offsetString + '[' + timezoneString + ']';
  return zdt.parse(stringToParse, dtf.ISO_ZONED_DATE_TIME);
}


logger.info('Starting Netatmo presence check');
var X_list = Java.from(itemRegistry.getItem('gNetatmoPresence').members);
for (var X_index in X_list) {
  X = X_list[X_index];
  msg = 'Netatmo presence: ';
  rawLabel = X.getLabel();
  lastSeen = X.getState();
  logger.info(rawLabel);
  logger.info(lastSeen);
  if ((zdt.now()) > lastSeen && zdt.now().minusMinutes(10) <= lastSeen) {
    events.sendCommand(rawLabel, 'ON');
    msg += String(rawLabel);
    msg += ' ON';
  } else {
    events.sendCommand(rawLabel, 'OFF');
    msg += String(rawLabel);
    msg += ' OFF';
  }
  logger.info(msg);
  msg = '';
  rawLabel = '';
  lastSeen = '';
}
logger.info('Ending Netatmo presence check');

Ok, I forgot that there are two ā€œcodeā€ tabs. Youā€™ll want to back out from the script action to the main page for the rule that shows the actions, triggers, and conditions and post the contents of the code l tab from there so that the entire time is captured.

The code you posted above is just showing the JavaScript that your Blockly ā€œcompilesā€ into. But I suspect you really want to show the entire rule.

We are going to make it :slight_smile:

Ā“Ā“Ā“
configuration: {}
triggers:

  • id: ā€œ1ā€
    configuration:
    cronExpression: 0 0/2 * * * ? *
    type: timer.GenericCronTrigger
    conditions: []
    actions:

  • inputs: {}
    id: ā€œ3ā€
    configuration:
    blockSource: ā€˜XmsgrawLabellastSeeninfoStarting Netatmo presence
    checkXgNetatmoPresencemsgNetatmo presence: rawLabelLabelMyItemXlastSeenStateMyItemXinfoabcrawLabelinfoabclastSeenANDGTlastSeenLTEminusMinutes10lastSeensendCommandONnetatmoCyrilrawLabelmsgrawLabelmsg
    ONsendCommandOFFnetatmoCyrilrawLabelmsgrawLabelmsg
    OFFinfoabcmsgmsgrawLabellastSeeninfoEnding Netatmo presence
    checkā€™
    type: application/javascript
    script: >
    var X, msg, rawLabel, lastSeen;

    var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
    
    
    var dtf = Java.type("java.time.format.DateTimeFormatter");
    
    
    var zdt = Java.type("java.time.ZonedDateTime");
    
    
    /* Try to detect the format based on its length */
    
    function getZonedDateTime(datetime) {
      datetime = String(datetime).replace('T', ' ')
      switch (datetime.length) {
        case 10: return zdt.parse(datetime + ' 00:00:00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
        case 16: return zdt.parse(datetime + ':00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
        case 19: return zdt.parse(datetime + '+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
        case 25: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));
        case 23: return zdt.parse(datetime + ' +00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSS z'));
        case 26: return zdt.parse(datetime + ' +00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSSS z'));
        case 29: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSz'));
        case 32: return zdt.parse(datetime, dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSSSSz'));
        case 28: return zdt.parse(datetime.slice(0,26) + ':' + datetime.slice(26,28), dtf.ofPattern('yyyy-MM-dd HH:mm:ss.SSSSz'));
        default: return zdt.parse(datetime);
      }
    }
    
    
    function createZonedDateTime(year, month, day, hour, minute, second, nano, offsetString, timezoneString) {
      stringToParse = '' + year;
      stringToParse += '-' + ('0' + month).slice(-2);
      stringToParse += '-' + ('0' + day).slice(-2);
      stringToParse += 'T' + ('0' + hour).slice(-2);
      stringToParse += ':' + ('0' + minute).slice(-2);
      stringToParse += ':' + ('0' + second).slice(-2);
      stringToParse += '.' + nano + offsetString + '[' + timezoneString + ']';
      return zdt.parse(stringToParse, dtf.ISO_ZONED_DATE_TIME);
    }
    
    
    
    logger.info('Starting Netatmo presence check');
    
    var X_list = Java.from(itemRegistry.getItem('gNetatmoPresence').members);
    
    for (var X_index in X_list) {
      X = X_list[X_index];
      msg = 'Netatmo presence: ';
      rawLabel = X.getLabel();
      lastSeen = X.getState();
      logger.info(rawLabel);
      logger.info(lastSeen);
      if ((zdt.now()) > lastSeen && zdt.now().minusMinutes(10) <= lastSeen) {
        events.sendCommand(rawLabel, 'ON');
        msg += String(rawLabel);
        msg += ' ON';
      } else {
        events.sendCommand(rawLabel, 'OFF');
        msg += String(rawLabel);
        msg += ' OFF';
      }
      logger.info(msg);
      msg = '';
      rawLabel = '';
      lastSeen = '';
    }
    
    logger.info('Ending Netatmo presence check');
    

    type: script.ScriptAction

Ā“Ā“Ā“

1 Like

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.