i8beef / HomeAutio.Mqtt.GoogleHome

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Attempt to setup a ROUTER device, not working in Google Home app

clmcavaney opened this issue · comments

I am attempting to add a ROUTER device to the googleDevices.json as per the documentation:
https://developers.home.google.com/cloud-to-cloud/guides/router
With this trait:
https://developers.home.google.com/cloud-to-cloud/traits/networkcontrol
Using this command:
https://developers.home.google.com/cloud-to-cloud/traits/networkcontrol#action.devices.commands.enabledisablenetworkprofile

HomeAutio.Mqtt.GoogleHome parses that all and presents the device.
The GoogleHome app shows the device and includes in the list of devices - I thought great this is going to work.

But there doesn't appear to be any action in the GoogleHome app to enable or disable the defined network profiles.
image
When you click on it:
image

I just wanted to check if there are known devices that are in the documentation that may not be implemented in the GoogleHome app that anybody knows of.

This is the section from googleDevices.json that I have in place:

  "router/firewall": {
    "id": "router/firewall",
    "type": "action.devices.types.ROUTER",
    "disabled": false,
    "willReportState": false,
    "roomHint": "Laundry",
    "name": {
      "defaultNames": [],
      "name": "Firewall rules",
      "nicknames": [
        "internet access"
      ]
    },
    "deviceInfo": {
      "manufacturer": "Testing",
      "model": "A1",
      "hwVersion": "1.0",
      "swVersion": "1.0"
    },
    "traits": [
      {
        "trait": "action.devices.traits.NetworkControl",
        "attributes": {
          "supportsEnablingNetworkProfile": true,
          "supportsDisablingNetworkProfile": true,
          "networkProfiles": [
            "Abigail",
            "Zoe"
          ]
        },
        "commands": {
          "action.devices.commands.EnableDisableNetworkProfile": {
            "Abigail.enable": "router/firewall/abigail",
            "Zoe.enable": "router/firewall/zoe"
          }
        },
        "state": {
          "networkEnabled": {
            "topic": "router/firewall"
          },
          "networkProfilesState.Abigail.enabled": {
            "topic": "router/firewall/abigail",
            "valueMap": [
              {
                "google": "true",
                "mqtt": "ON",
                "type": "value"
              },
              {
                "google": "false",
                "mqtt": "OFF",
                "type": "value"
              }
            ]
          },
          "networkProfilesState.Zoe.enabled": {
            "topic": "router/firewall/zoe",
            "valueMap": [
              {
                "google": "true",
                "mqtt": "ON",
                "type": "value"
              },
              {
                "google": "false",
                "mqtt": "OFF",
                "type": "value"
              }
            ]
          }
        },
        "challenge": null
      }
    ],
    "customData": null
  },

There are actually only a few traits that are actionable in the Google Home app. Voice commands should all work as expected, but Google's track record for delivering new Home features is... not great.

To me knowledge there's no documented list of implemented traits, but from experience, its basically lights, fans, temp control, and as of the "beta" which I'm sure will last 3 freaking years, media control remotes, (some) robot vac stuff, and (google only) cameras, and SOMETIMES garage doors (its finicky).

Ah - that explains it then. I will see if there are any voice commands for the ROUTER device.
If not, I might have to implement it as a "light" 😜

I was just testing this via voice commands, and I can see request information coming through, but when I tried to change Serilog to Verbose, but the logs remained as [INF] only.

It's like that change in configuration is making no difference.

Because there's nothing more verbose than INFO in this app 😄

What are you looking for?

Oh - I thought DEBUG was more verbose - I was wanting to see how HomeAutio was processing the requests from Google. I can see that it is receiving the request, but isn't creating any MQTT messages in response to the EXECUTE command coming through.

I saw some _log.LogDebug() calls in the code.

e.g.

homeautio.mqtt.googlehome  | [00:30:27 INF] Received EXECUTE intent for commands: action.devices.commands.EnableDisableNetworkProfile

But there is no subsequent MQTT message received at the topic specified (see config above)

Oh actually I'm wrong. Sorry it's been a long time since I used them, but Verbose SHOULD enable certain logs around token handshakes (used during initial development), AND should enable the RequestResponseLoggingMiddleware which would log out the request / response from incoming Google requests.

I haven't used that particular command before so I don't have known good examples... the "examples" are technically generated from Google's schema files to give people a starting point, in some cases they might not be completely correct....

Keep in mind if you change the config you have to restart the container?

G'day Michael,
Yep, I am stopping and starting the container each time.

I can see the request coming in from Google, but there is no subsequent MQTT action from that EXECUTE intent.
Strange as other EXECUTE intents for lights work.

Here is a log snippet (with Verbose for Serilog):

homeautio.mqtt.googlehome  | [05:21:58 INF] Request starting HTTP/1.1 POST http://googlehome.<redacted>/smarthome application/json;charset=UTF-8 538
homeautio.mqtt.googlehome  | [05:21:58 INF] Executing endpoint 'HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController.Post (HomeAutio.Mqtt.GoogleHome)'
homeautio.mqtt.googlehome  | [05:21:58 INF] Route matched with {action = "Post", controller = "GoogleHome"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Post(HomeAutio.Mqtt.GoogleHome.Models.Request.Request) on controller HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController (HomeAutio.Mqtt.GoogleHome).
homeautio.mqtt.googlehome  | [05:21:58 INF] Received EXECUTE intent for commands: action.devices.commands.EnableDisableNetworkProfile
homeautio.mqtt.googlehome  | [05:21:58 INF] Executing OkObjectResult, writing value of type 'HomeAutio.Mqtt.GoogleHome.Models.Response.Response'.
homeautio.mqtt.googlehome  | [05:21:58 INF] Executed action HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController.Post (HomeAutio.Mqtt.GoogleHome) in 15.0175ms
homeautio.mqtt.googlehome  | [05:21:58 INF] Executed endpoint 'HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController.Post (HomeAutio.Mqtt.GoogleHome)'
homeautio.mqtt.googlehome  | [05:21:58 INF] Request finished HTTP/1.1 POST http://googlehome.<redacted>/smarthome application/json;charset=UTF-8 538 - 200 155 application/json;+charset=utf-8 21.4664ms

Yeah something's broken there from the updates. It won't take me limiting it down to "Warning" or "Error" either, but it IS writing to the right file sink, so its at least PARTIALLY reading configuration... gonna have to dig into Serilog to figure out why its ignoring the configuration here.

For your actual issue, you might try subscribing to the command delegation MQTT topic for this device, which would be something like google/home/execution/DEVICENAME/COMMANDNAME. If you aren't getting THAT then it must for some reason think your device configuration doesn't actually have that command enabled for the device (https://github.com/i8beef/HomeAutio.Mqtt.GoogleHome/blob/master/src/HomeAutio.Mqtt.GoogleHome/Services/MqttService.cs#L208).

Ah - I had forgotten about the google/ MQTT topic. Thanks for the reminder.

This is what I see:

google/home/execution/router/firewall/EnableDisableNetworkProfile {"enable":false,"followUpToken":"00dbd7<redacted>d86","profile":"Zoe"}
google/home/query/lastRequest {"devices":[{"id":"router/firewall","customData":null}],"time":"2023-04-05T22:53:07.2374908+00:00"}

What I am wondering is about the flattening of layered states and/or commands.

As shown above I have:

...
        "commands": {
          "action.devices.commands.EnableDisableNetworkProfile": {
            "Abigail.enable": "router/firewall/abigail",
            "Zoe.enable": "router/firewall/zoe"
          }
        },
...

So this is a flattened representation as mentioned here.
I am wondering if the execution request (shown above) is matching with that correctly?

And then the state, it has enabled (seen here https://developers.home.google.com/cloud-to-cloud/traits/networkcontrol#:~:text=currently%20being%20run.-,networkProfilesState,-Object) but I wonder if it should actually be enable. (I did try enable for the state, but that didn't appear to make any difference either).

...
        "state": {
          "networkEnabled": {
            "topic": "router/firewall"
          },
          "networkProfilesState.Abigail.enabled": {
            "topic": "router/firewall/abigail",
            "valueMap": [
              {
                "google": "true",
                "mqtt": "ON",
                "type": "value"
              },
              {
                "google": "false",
                "mqtt": "OFF",
                "type": "value"
              }
            ]
          },
...

Ah, your usage is off here. That object is basically exactly what Google is sending through. The mapping to an MQTT topic is PER PROPERTY, which means

{
  enabled: true,
  profile: "Test"
}

Could be setup to send through TWO MQTT topics , one for "enabled" and one for "profile"... but you can't actually process like that for this command, because the two values are not independent, "profile" tells you WHICH profile to "enable". Basically there are a couple TYPES of command approaches Google uses. A lot of the simple devices at just "a bag of independent properties" that can all be set independent of each other (and thats what the built in MQTT topic mapping is for). Some of them are more like RPC calls, where you have to process the ENTIRE command with MULTIPLE arguments that interact to do something useful, and that's what the Command Delegation approach is for (but you have to implement your logic elsewhere for parsing that command and doing the right things).

(And then there's cameras which are a special king of one-off hell....)

IE your config would have to be something like this with MQTT mapping, which could be fudged to work IF you only had ONE profile (ie, basically "profile" wouldn't be used):

        "commands": {
          "action.devices.commands.EnableDisableNetworkProfile": {
            "enable": "router/firewall/enable",
            "profile": "router/firewall/profile"
          }
        },

But then won't do what I think you want, which is having two different network profiles that you can enable / disable at will.

To do what YOU want to do, you're only option would be to use the command delegation approach, listen to google/home/execution/DEVICENAME/COMMANDNAME, and then process the entire message somewhere (node-red, etc.?).

Hey @i8beef,
Another (semi) related question.
Do you know if Secondary User Verification is handled by HomeAutio?

I see in the example googleDevices.json file there is a challenge clause, but there isn't an example.

I suspect that HomeAutio needs to respond to an EXECUTE request with a challenge, and HomeAutio would know to do that from the googleDevices.json configuration.
Is that correct?

They are! If you use the web interface to edit the googleDevices.json file there are options there to generate it for any given trait, but they should look like this:

...
    "traits": [
      {
        "trait": "action.devices.traits.ArmDisarm",
        "attributes": null,
        "commands": {
          ...
        },
        "state": {
         ...
        },
        "challenge": {
          "type": "pin",
          "pin": "1234"
        }
      },

or the "ack" version:

        "challenge": {
          "type": "ack"
        }

That is sensationally brilliant!
I couldn't figure out the syntax, thanks for those examples.

FYI, I fixed the logging settings thing. The app loads configuration TWICE actually, once for initial startup that it needs to setup logging, and once for the actual app. The "at startup" load was still looking for the appsettings.Production.json in the /app/config directory, while the NORMAL one just looked for it in the /app/appsettings.Production.json location.

They should both load from the right file now, so it'll respect your logging MinimumLevel setting.

That's great news - thanks Michael