i8beef / HomeAutio.Mqtt.GoogleHome

MIT License
215 stars 29 forks source link

SensorState & serialization error #87

Closed sognen closed 4 years ago

sognen commented 4 years ago

Hi, This is not necessarily a bug, but since I am getting HTTP error with the log listing a serialization error I thought I would check.

I am trying to configure a smokeDetector but when creating the SensorState trait it throws at HTTP 500 error and the log listing a serialization error.

[Error] Connection id ""0HM182LLBHT27"", Request id ""0HM182LLBHT27:00000004"": An unhandled exception was thrown by the application. Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'HomeAutio.Mqtt.GoogleHome.Models.State.DeviceState' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.

My config is as follows (it appears that the problem is with the state section)

Attributes: { "sensorStatesSupported": [ { "name": "SmokeLevel", "numericCapabilities": { "rawValueUnit": "PARTS_PER_MILLION" }, "descriptiveCapabilities": { "availableStates": [ "smoke detected", "high", "no smoke detected" ] } } ] }

Commands: {}

State: { "currentSensorStateData": [ { "name": "SmokeLevel", "currentSensorState": { "topic": "google/home/topic", "googleType": "string", "valueMap": [] } } ] }

Anyone, please share if anyone has a working sample of device with SensorState.

i8beef commented 4 years ago

That's not going to be supported correctly. The state is actually supposed to be a flattened key-value mapping, so you'd expect something maybe more like

{
  "currentSensorStateData[0].name": {
    "topic": "google/home/topic",
    "googleType": "string",
    "valueMap": []
  },
  "currentSensorStateData[0].currentSensorState": {
    "topic": "google/home/topic",
    "googleType": "string",
    "valueMap": []
  }
}

But it doesn't support arrays, and frankly Im not even sure something like that would work without throwing wrenches into reportState... I'd have to look at if I can do this generically like that....

Maintaining a custom handler per trait / command, which I've tried several times, is a maintenance nightmare. But being able to handle arbitrary weird Google decisions is starting to paint me into a corner...

For now: this isn't supported appropriately. I'll look at supporting arrays in this structure, but its gonna be a while.

sognen commented 4 years ago

Thank you for your quick response.

i8beef commented 4 years ago

Ok I might have lied. I played with this for about an hour and came up with a way that I THINK will work for you. It should be publishing right now. You'll want to map your state like this:

{
  "currentSensorStateData.[0].name": {
    "topic": "google/home/topic1",
    "googleType": "string",
    "valueMap": []
  },
  "currentSensorStateData.[0].currentSensorState": {
    "topic": "google/home/topic2",
    "googleType": "string",
    "valueMap": []
  },
  "currentSensorStateData.[1].name": {
    "topic": "google/home/topic3",
    "googleType": "string",
    "valueMap": []
  },
  "currentSensorStateData.[1].currentSensorState": {
    "topic": "google/home/topic4",
    "googleType": "string",
    "valueMap": []
  }
}

Try it and let me know if it actually works...

sognen commented 4 years ago

Hi, I downloaded the latest build and added the above state, i.e.,

{ "currentSensorStateData.[0].SmokeLevel": { "topic": "google/home/topic1", "googleType": "string", "valueMap": [] }, "currentSensorStateData.[0].currentSensorState": { "topic": "google/home/topic2", "googleType": "string", "valueMap": [] } }

I can see from the log that I can an incoming QUERY request. The assistant is giving me "Sorry I cant reach .... please try again.".

The log says: [05:25:05 INF] Received QUERY intent for devices: smoke [05:25:05 INF] Executing ObjectResult, writing value of type 'HomeAutio.Mqtt.GoogleHome.Models.Response.Response'. [05:25:05 INF] Executed action HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController.Post (HomeAutio.Mqtt.GoogleHome) in 1.1706ms [05:25:05 INF] Executed endpoint 'HomeAutio.Mqtt.GoogleHome.Controllers.GoogleHomeController.Post (HomeAutio.Mqtt.GoogleHome)' [05:25:05 INF] Request finished in 3.2988ms 200 application/json; charset=utf-8

i8beef commented 4 years ago

The above was just an example, you still need to include the .name property for each of those I think. You can use a static valueMap for those since it's just going to always return one static value:

  "currentSensorStateData.[0].name": {
    "topic": null,
    "googleType": "string",
    "valueMap": [
      {
        "type": "static",
        "google": "AirQuality"
      }
    ]
  },
  "currentSensorStateData.[0].currentSensorState": {
    "topic": "google/home/topic",
    "googleType": "string",
    "valueMap": []
  }
sognen commented 4 years ago

Hi,

Many thanks for your help with this one. So applied the template provided above, and still no cigar. I still get the Cannot reach error message. I have also tried the following:

Log looks fine.

i8beef commented 4 years ago

What do you get when you attempt to validate the SYNC Response? There's a big orange button on the home page for that which you can click and then just dump the JSON blob into Google's validator tool to see what it thinks is incorrect.

sognen commented 4 years ago

No errors found. I typically run this check whenever adding/updating devices.

Device with sensorstate can be seen in the Home app. Unfortunately it is one of those devices that is voice only.

i8beef commented 4 years ago

Can't REACH sounds like something else... if you're passing the validation, then it sounds like its right (can you post the output of the validation for the device in question just so I can eyeball it?)

  1. You remembered to "sync my device" after changes right? Does that fail?
  2. If you remove the device temporarily and do a sync does it work?
sognen commented 4 years ago

Hi,

  1. Confirmed - I always sync devices after changes. This appears to work good as the assistant confirms that my devices are synced. Any updated/new devices are reflected in the Google Home app.

  2. I have just tested removing the device, re-synced and can confirm that the device becomes "unknown" to the assistant, and also listed as unlinked and removed from the google home app.

It appears to me that it has something to do with what is being sent back to Google after a query.

Attached you can find the output of the validation and my googleDevices.json.

homeautio-config.zip

The device is called smokeDetector.

i8beef commented 4 years ago

I was incorrect that a static map would work for you. That only works for GetCameraStream. I've expanded it to work with any state param that has a null topic. Try that.

sognen commented 4 years ago

Brilliant. Downloaded latest build and it now responds correctly. Thank you.

For the benefit of others that are looking to use trait SensorState, here is a working example:

{ "currentSensorStateData.[0].name": { "topic": null, "googleType": "string", "valueMap": [ { "type": "static", "google": "SmokeLevel" } ] }, "currentSensorStateData.[0].currentSensorState": { "topic": "bedroom/smokeDetector/sensorState", "googleType": "string", "valueMap": [] } }

i8beef commented 4 years ago

I am glad to hear that actually worked. Just remember if we ever meet you owe me a beer. 😄

Cheers mate

sognen commented 4 years ago

Sure thing. :)

sognen commented 4 years ago

Sure thing. :)

sognen commented 4 years ago

Sure thing. :)

sognen commented 4 years ago

I meant to say yesterday, let me know if I can be of any assistance, testing, writing documentation, ... Happy to help.