Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add switch entity for Home/Away control #100

Open
schmittx opened this issue Sep 22, 2022 · 5 comments
Open

Add switch entity for Home/Away control #100

schmittx opened this issue Sep 22, 2022 · 5 comments
Labels
enhancement New feature or request

Comments

@schmittx
Copy link

Description

Another feature lacking from Nest SDM is the ability to toggle home/away for the structure.

The structure.xxx data bucket already includes the away boolean parameter, so I believe it should be an easy addition (no protobufs required?).

Device (optional)

Structure

Additional information

No response

@schmittx schmittx added the enhancement New feature or request label Sep 22, 2022
@sidplayos2
Copy link

+1 for this.

@iMicknl
Copy link
Owner

iMicknl commented Dec 16, 2023

It took a while, but I will have a look again. Can you try to execute this via https://home.nest.com/ and capture the POST request (JSON). I don't have a thermostat, so I am not able to add this.

Is this not supported in the Nest integration in core?

@sidplayos2
Copy link

sidplayos2 commented Dec 17, 2023

Hi Mick,

I did speak to Allen Porter about this a while ago, and it was because this HomeAway Sensor/Switch is not directly in the SDM API, same reason the Protects are not in the Nest Core.

I did find this switch does exist in the full blown HomeKit/Homebridge nest API (https://github.com/chrisjshull/homebridge-nest) which I understand the Protect integration is based on. If you scroll down to the Feature Options of that page you will see:

"HomeAway.AsOccupancySensorAndSwitch" - create Home/Away indicator as an OccupancySensor and a Switch

I found the Home/Away code is in the file lib/nest-homeaway-accessory.js
Happy to trace the POST anyway, my thinking was if the logic below is similar to what we want to achieve?

In particular the getHome() and setHome() functions look relevant.

/**
 * Created by Adrian Cable on 7/26/19.
 */

'use strict';

const { NestDeviceAccessory, Service, Characteristic } = require('./nest-device-accessory')();

const nestDeviceDescriptor = {
    deviceType: 'home_away_sensor',
    deviceGroup: 'home_away_sensors',
    deviceDesc: 'Nest Home/Away Sensor'
};

class NestHomeAwayAccessory extends NestDeviceAccessory {
    constructor(conn, log, device, structure, platform) {
        super(conn, log, device, structure, platform);

        if (this.platform.optionSet('HomeAway.AsOccupancySensor', this.device.serial_number, this.device.device_id) || this.platform.optionSet('HomeAway.AsOccupancySensorAndSwitch', this.device.serial_number, this.device.device_id)) {
            const homeService = this.addService(Service.OccupancySensor, this.homeKitSanitize(this.device.name), 'home_occupied_sensor.' + this.device.device_id);
            this.bindCharacteristic(homeService, Characteristic.OccupancyDetected, this.device.name, this.getHome);
        }

        if (!this.platform.optionSet('HomeAway.AsOccupancySensor', this.device.serial_number, this.device.device_id)) {
            const homeService = this.addService(Service.Switch, this.homeKitSanitize(this.device.name), 'home_occupied.' + this.device.device_id);
            this.bindCharacteristic(homeService, Characteristic.On, this.device.name, this.getHome, this.setHome);
        }

        this.updateData();
    }

    getHome() {
        if (!this.structure.new_structure_id) {
            this.conn.verbose('Warning: getting Home/Away status using REST API - may lead to issues.');
        }
        return !this.device.away;
    }

    setHome(home, callback) {
        if (this.structure.new_structure_id) {
            // Set using protobuf API
            let cmd = {
                traitLabel: 'structure_mode',
                command: {
                    type_url: 'type.nestlabs.com/nest.trait.occupancy.StructureModeTrait.StructureModeChangeRequest',
                    value: {
                        structureMode: home ? 'STRUCTURE_MODE_HOME' : 'STRUCTURE_MODE_AWAY',
                        reason: 'STRUCTURE_MODE_REASON_EXPLICIT_INTENT',
                        userId: {
                            resourceId: this.structure.user_id
                        }
                    }
                }
            };

            this.conn.protobufSendCommand([ cmd ], 'STRUCTURE_' + this.structure.new_structure_id).asCallback(callback);
        } else {
            // Set using REST API
            this.conn.verbose('Warning: setting Home/Away status using REST API - may lead to issues.');
            let val = !home ? 'away' : 'home';
            this.setPropertyAsync('structure', 'away', val).asCallback(callback);
        }
    }
}

module.exports = function() {
    Object.keys(nestDeviceDescriptor).forEach(key => NestHomeAwayAccessory[key] = NestHomeAwayAccessory.prototype[key] = nestDeviceDescriptor[key]);
    return NestHomeAwayAccessory;
};

@iMicknl
Copy link
Owner

iMicknl commented Dec 18, 2023

They are using Protobuf (a different protocol) for this, which we didn't implement for the Nest Protect integration (yet).

@sidplayos2
Copy link

Hi Mick,

So I've traced the POST request down in Chrome Dev Tools and it seems they are not using application/json for Content-Type but instead application/x-protobuf in the actual request headers:

Request URL:
https://grpc-web.production.nest.com/nestlabs.gateway.v1.ResourceApi/SendCommand
Request Method:
POST
Status Code:
200 OK
Remote Address:
34.98.67.105:443
Referrer Policy:
origin
Access-Control-Allow-Origin:
*
Alt-Svc:
h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Transfer-Encoding:
base64
Content-Type:
application/x-protobuf.google.rpc.streambody
<--------- Response Content-Type
Date:
Wed, 27 Dec 2023 23:46:48 GMT
Server:
nginx/1.11.13
Via:
1.1 google
:authority:
grpc-web.production.nest.com
:method:
POST
:path:
/nestlabs.gateway.v1.ResourceApi/SendCommand
:scheme:
https
Accept:
/
Accept-Encoding:
gzip, deflate, br
Accept-Language:
en-US,en;q=0.9
Authorization:
Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Length:
219
Content-Type:
application/x-protobuf
<--------- Request Content-Type
Origin:
https://home.nest.com
Referer:
https://home.nest.com/
Request-Id:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Sec-Ch-Ua:
"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
Sec-Ch-Ua-Mobile:
?0
Sec-Ch-Ua-Platform:
"Windows"
Sec-Fetch-Dest:
empty
Sec-Fetch-Mode:
cors
Sec-Fetch-Site:
same-site
User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
X-Accept-Content-Transfer-Encoding:
base64
X-Accept-Response-Streaming:
true
X-Nl-Webapp-Version:
NlAppSDKVersion/9.5.3 NlSchemaVersion/2.1.20-336-g3111f722b

And the request payload looks to be the serialized class object:

payload

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants