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

New Device presentation for Forwarrding (API v1 part 1) #375

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

timcowlishaw
Copy link
Contributor

@timcowlishaw timcowlishaw commented Nov 13, 2024

New presentation logic, for API v1, used to produce data to be sent via MQTT forwarding, and for "pre-release" API endpoints at /v1/devices and /v1/devices/:id.

This "rationalises" and simplifies the shape of the JSON representations of all models, as well as refactoring the presentation logic to be simpler and more reusable. It also allows us to "batch forward" multiple readings for a device in a single call to a sidekiq job, which should improve efficiency when we start forwarding postprocessing readings.

This is required for MQTT forwarding of postprocessing data, as the existing device json serialization is very tightly coupled to the view logic and the device representation in the db, which has the result that there's no particularly satisfactory way to send readings that are not the latest recorded for the device over MQTT.

🚨 REQUIRES MIGRATION ON DEPLOY 🚨

An example of a device json representation in the new format:

{
  "id": 14801,
  "uuid": "8615aabb-4755-4537-9776-78aa18e79836",
  "name": "LabOffice-CO2",
  "description": "Smart Citizen Kit 2.1 with Urban Sensor Board",
  "state": "has_published",
  "system_tags": [
    "offline",
    "outdoor"
  ],
  "user_tags": [
    "airlab-isglobal"
  ],
  "last_reading_at": "2021-11-29T17:22:01Z",
  "created_at": "2021-11-25T12:01:43Z",
  "updated_at": "2024-06-24T17:45:57Z",
  "notify": {
    "stopped_publishing": false,
    "low_battery": false
  },
  "location": {
    "exposure": "outdoor",
    "elevation": null,
    "latitude": 41.38396,
    "longitude": 2.18649,
    "geohash": "sp3e3v8phc",
    "city": "Barcelona",
    "country_code": "ES",
    "country": "Spain"
  },
  "hardware": {
    "name": "SCK 2.1 CO2",
    "type": "SCK",
    "version": "2.1",
    "slug": "sck:2,1:co2",
    "last_status_message": null,
    "unauthorized_fields": [
      "last_status_message"
    ]
  },
  "owner": {
    "id": 8024,
    "uuid": "a358cb6a-4af2-41ef-a135-0516591631eb",
    "role": "citizen",
    "username": "AIRLAB_ISGlobal",
    "profile_picture": "",
    "location": {
      "city": null,
      "country": null,
      "country_code": null
    },
    "created_at": "2021-05-27T10:46:12Z",
    "updated_at": "2022-01-19T11:31:46Z",
    "unauthorized_fields": [
      "email",
      "legacy_api_key"
    ]
  },
  "components": [
    {
      "sensor": {
        "id": 10,
        "name": "Battery SCK",
        "description": "Custom Circuit",
        "unit": "%",
        "created_at": "2015-02-02T18:18:00Z",
        "updated_at": "2020-12-11T16:12:40Z",
        "uuid": "c9ff2784-53a7-4a84-b0fc-90ecc7e313f9",
        "measurement": {
          "id": 7,
          "name": "battery",
          "description": "The SCK remaining battery level in percentage.",
          "uuid": "c5964926-c2d2-4714-98b5-18f84c6f95c1"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 99,
      "previous_value": 99
    },
    {
      "sensor": {
        "id": 14,
        "name": "BH1730FVC - Light",
        "description": "Digital Ambient Light Sensor",
        "unit": "lux",
        "created_at": "2015-02-02T18:24:56Z",
        "updated_at": "2021-05-07T16:23:50Z",
        "uuid": "ac4234cf-d2b7-4cfa-8765-9f4477e2de5f",
        "measurement": {
          "id": 3,
          "name": "Light",
          "description": "Lux is a measure of how much light is spread over a given area. A full moon clear night is around 1 lux, inside an office building you usually have 400 lux and a bright day can be more than 20000 lux.",
          "uuid": "50aa0431-86ac-4340-bf51-ad498ee35a3b"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 340,
      "previous_value": 340
    },
    {
      "sensor": {
        "id": 53,
        "parent_id": 52,
        "name": "ICS43432 - Noise",
        "description": "I2S Digital Mems Microphone with custom Audio Processing Algorithm",
        "unit": "dBA",
        "created_at": "2018-05-03T10:42:47Z",
        "updated_at": "2018-05-03T10:42:54Z",
        "uuid": "f508548e-3fd1-44aa-839b-9bd147168481",
        "measurement": {
          "id": 4,
          "name": "Noise Level",
          "description": "dB's measure sound pressure difference between the average local pressure and the pressure in the sound wave.  A quiet library is below 40dB, your house is around 50dB and a diesel truck in your street 90dB.",
          "uuid": "2841719f-658e-40df-a14a-74a86adc1410"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 31.05,
      "previous_value": 31.05
    },
    {
      "sensor": {
        "id": 55,
        "parent_id": 54,
        "name": "Sensirion SHT31 - Temperature",
        "description": "Temperature",
        "unit": "ºC",
        "created_at": "2018-05-03T10:47:15Z",
        "updated_at": "2023-07-14T17:16:19Z",
        "uuid": "384e46a2-80dd-481e-a9fc-cfbd512f9f43",
        "measurement": {
          "id": 1,
          "name": "Air Temperature",
          "description": "Air temperature is a measure of how hot or cold the air is. It is the most commonly measured weather parameter. Air temperature is dependent on the amount and strength of the sunlight hitting the earth, and atmospheric conditions, such as cloud cover and humidity, which trap heat.",
          "uuid": "b3f44b63-0a17-4d84-bbf1-4c17764b7eae"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 19.69,
      "previous_value": 19.69
    },
    {
      "sensor": {
        "id": 56,
        "parent_id": 54,
        "name": "Sensirion SHT31 - Humidity",
        "description": "Humidity",
        "unit": "%",
        "created_at": "2018-05-03T10:47:17Z",
        "updated_at": "2023-07-14T17:16:44Z",
        "uuid": "b6543356-0066-4bea-8ad2-687e282f9c20",
        "measurement": {
          "id": 2,
          "name": "Relative Humidity",
          "description": "Relative humidity is a measure of the amount of moisture in the air relative to the total amount of moisture the air can hold. For instance, if the relative humidity was 50%, then the air is only half saturated with moisture.",
          "uuid": "9cbbd396-5bd3-44be-adc0-7ffba778072d"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 50.02,
      "previous_value": 50.02
    },
    {
      "sensor": {
        "id": 58,
        "parent_id": 57,
        "name": "NXP MPL3115A2 - Barometric Pressure",
        "description": "Digital Barometric Pressure Sensor",
        "unit": "kPa",
        "created_at": "2018-05-03T10:49:17Z",
        "updated_at": "2023-07-14T16:52:14Z",
        "uuid": "cadd2459-6559-4d92-aed1-ba04c557fed8",
        "measurement": {
          "id": 25,
          "name": "Barometric Pressure",
          "description": "Barometric pressure is the pressure within the atmosphere of Earth. In most circumstances atmospheric pressure is closely approximated by the hydrostatic pressure caused by the weight of air above the measurement point.",
          "unit": "NULL",
          "uuid": "2a944e9d-073d-49ed-8dc7-e376495f283d"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 101.49,
      "previous_value": 101.49
    },
    {
      "sensor": {
        "id": 87,
        "parent_id": 86,
        "name": "Plantower PMS5003 - PM2.5",
        "description": "Particle Matter PM 2.5",
        "unit": "ug/m3",
        "created_at": "2018-05-22T13:20:34Z",
        "updated_at": "2023-05-23T11:13:07Z",
        "uuid": "9ee89ac2-0482-46dd-905f-0b7a1bb12c55",
        "measurement": {
          "id": 14,
          "name": "PM 2.5",
          "description": "PM stands for particulate matter: the term for a mixture of solid particles and liquid droplets found in the air. Some particles, such as dust, dirt, soot, or smoke, are large or dark enough to be seen with the naked eye.",
          "uuid": "c8ecda46-c430-4cbc-9ad4-5ea8a07c5820"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 0,
      "previous_value": 0
    },
    {
      "sensor": {
        "id": 88,
        "parent_id": 86,
        "name": "Plantower PMS5003 - PM10",
        "description": "Particle Matter PM 10",
        "unit": "ug/m3",
        "created_at": "2018-05-22T13:20:34Z",
        "updated_at": "2023-05-23T11:12:06Z",
        "uuid": "c2072a22-4d81-4d7c-a38c-af9458b8f309",
        "measurement": {
          "id": 13,
          "name": "PM 10",
          "description": "PM stands for particulate matter: the term for a mixture of solid particles and liquid droplets found in the air. Some particles, such as dust, dirt, soot, or smoke, are large or dark enough to be seen with the naked eye.",
          "uuid": "30e5b614-ab7e-46bc-b6f7-fa9a30926ce9"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 0,
      "previous_value": 0
    },
    {
      "sensor": {
        "id": 89,
        "parent_id": 86,
        "name": "Plantower PMS5003 - PM1.0",
        "description": "Particle Matter PM 1",
        "unit": "ug/m3",
        "created_at": "2018-05-22T13:20:34Z",
        "updated_at": "2023-05-23T11:13:03Z",
        "uuid": "a4b9efba-241f-446e-9cf2-918f25efd0c5",
        "measurement": {
          "id": 27,
          "name": "PM 1",
          "description": "PM stands for particulate matter: the term for a mixture of solid particles and liquid droplets found in the air. Some particles, such as dust, dirt, soot, or smoke, are large or dark enough to be seen with the naked eye.",
          "uuid": "9759c2fd-15d8-424b-adcc-d6efcf940f6e"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 0,
      "previous_value": 0
    },
    {
      "sensor": {
        "id": 112,
        "parent_id": 111,
        "name": "AMS CCS811 - eCO2",
        "description": "Equivalent Carbon Dioxide Digital Indoor Sensor",
        "unit": "ppm",
        "created_at": "2019-03-21T16:43:37Z",
        "updated_at": "2019-03-21T16:43:37Z",
        "uuid": "995343c9-12ac-40c0-b6b9-19699e524f86",
        "measurement": {
          "id": 46,
          "name": "eCO2",
          "description": "Equivalent CO2 is the concentration of CO2 that would cause the same level of radiative forcing as a given type and concentration of greenhouse gas. Examples of such greenhouse gases are methane, perfluorocarbons, and nitrous oxide. CO2 is primarily a by-product of human metabolism and is constantly being emitted into the indoor environment by building occupants. CO2 may come from combustion sources as well. Associations of higher indoor carbon dioxide concentrations with impaired work performance and increased health symptoms have been attributed to correlation of indoor CO2 with concentrations of other indoor air pollutants that are also influenced by rates of outdoor-air ventilation.",
          "uuid": "b6fee847-2bb6-4e1e-8e39-979612e2beb9"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 488,
      "previous_value": 488
    },
    {
      "sensor": {
        "id": 113,
        "parent_id": 111,
        "name": "AMS CCS811 - TVOC",
        "description": "Total Volatile Organic Compounds Digital Indoor Sensor",
        "unit": "ppb",
        "created_at": "2019-03-21T16:43:37Z",
        "updated_at": "2019-03-21T16:43:37Z",
        "uuid": "0c2a1afc-dc08-4066-aacb-0bde6a3ae6f5",
        "measurement": {
          "id": 47,
          "name": "TVOC",
          "description": "Total volatile organic compounds is a grouping of a wide range of organic chemical compounds to simplify reporting when these are present in ambient air or emissions. Many substances, such as natural gas, could be classified as volatile organic compounds (VOCs).",
          "uuid": "c6f9a729-1782-4da1-adc9-e88b7143e45c"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 13,
      "previous_value": 13
    },
    {
      "sensor": {
        "id": 158,
        "name": "SCD30 - CO2",
        "description": "Carbon Dioxide",
        "unit": "ppm",
        "created_at": "2020-12-11T15:57:05Z",
        "updated_at": "2021-05-07T16:23:09Z",
        "uuid": "96d2631f-1a14-4bdb-99e6-ff542330d805",
        "measurement": {
          "id": 65,
          "name": "CO2",
          "description": "Carbon dioxide is a colorless gas produced by the combustion of all carbon-based fuels, such as methane (natural gas), petroleum distillates (gasoline, diesel, kerosene, propane), coal, wood and generic organic matter. Carbon dioxide is the most significant long-lived greenhouse gas in Earth's atmosphere.",
          "uuid": "c2f598bd-994e-4179-ac39-e2428ed47d95"
        },
        "tags": []
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 609,
      "previous_value": 609
    },
    {
      "sensor": {
        "id": 160,
        "parent_id": 162,
        "name": "SCD30 - Temperature",
        "description": "Sensirion SCD30 Temperature",
        "unit": "ºC",
        "created_at": "2021-05-07T13:57:23Z",
        "updated_at": "2021-05-07T16:16:23Z",
        "uuid": "88e8ed25-a5f9-4b85-a5c8-c0496e50c448",
        "measurement": {
          "id": 1,
          "name": "Air Temperature",
          "description": "Air temperature is a measure of how hot or cold the air is. It is the most commonly measured weather parameter. Air temperature is dependent on the amount and strength of the sunlight hitting the earth, and atmospheric conditions, such as cloud cover and humidity, which trap heat.",
          "uuid": "b3f44b63-0a17-4d84-bbf1-4c17764b7eae"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 23.44,
      "previous_value": 23.44
    },
    {
      "sensor": {
        "id": 161,
        "parent_id": 162,
        "name": "SCD30 - Humidity",
        "description": "Sensirion SCD30 Humidity",
        "unit": "%",
        "created_at": "2021-05-07T13:57:44Z",
        "updated_at": "2021-05-07T16:16:37Z",
        "uuid": "72583527-4192-4cb2-a118-63619b01d8e7",
        "measurement": {
          "id": 2,
          "name": "Relative Humidity",
          "description": "Relative humidity is a measure of the amount of moisture in the air relative to the total amount of moisture the air can hold. For instance, if the relative humidity was 50%, then the air is only half saturated with moisture.",
          "uuid": "9cbbd396-5bd3-44be-adc0-7ffba778072d"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z",
      "latest_value": 33.89,
      "previous_value": 33.89
    },
    {
      "sensor": {
        "id": 165,
        "name": "Plantower PMS5003 - PN0.3",
        "description": "Particle Matter PN0.3",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:37Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "dd9546ff-da17-499b-b328-b1862a0e495d",
        "measurement": {
          "id": 40,
          "name": "PN0.3",
          "description": "Particle Number Concentration below 0.3um",
          "uuid": "931a49ad-b24c-4554-a671-2088004b3b1b"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    },
    {
      "sensor": {
        "id": 166,
        "name": "Plantower PMS5003 - PN0.5",
        "description": "Particle Matter PN0.5",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:37Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "5ed7b7f0-cd03-4751-bc0d-dd606ae82a17",
        "measurement": {
          "id": 41,
          "name": "PN0.5",
          "description": "Particle Number Concentration from previous size to 0.5um",
          "uuid": "fffc6df4-2d2d-48d4-834f-cea2e18d6862"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    },
    {
      "sensor": {
        "id": 167,
        "name": "Plantower PMS5003 - PN1.0",
        "description": "Particle Matter PN1.0",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:37Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "aac188e2-ab8a-4c62-bf23-dd5340551b1e",
        "measurement": {
          "id": 42,
          "name": "PN1.0",
          "description": "Particle Number Concentration from previous size to 1.0um",
          "uuid": "16308fc4-78ac-4ce9-a5b1-c32fb78d0c01"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    },
    {
      "sensor": {
        "id": 168,
        "name": "Plantower PMS5003 - PN2.5",
        "description": "Particle Matter PN2.5",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:37Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "7ba875d4-74ee-48cc-b3ad-a06fb130c923",
        "measurement": {
          "id": 43,
          "name": "PN2.5",
          "description": "Particle Number Concentration from previous size to 2.5um",
          "uuid": "84900487-04a1-4e77-aec9-d15c92a3074b"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    },
    {
      "sensor": {
        "id": 169,
        "name": "Plantower PMS5003 - PN5.0",
        "description": "Particle Matter PN5.0",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:37Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "58bb65a9-fb35-4268-b5e2-a34c6b2f06e4",
        "measurement": {
          "id": 44,
          "name": "PN5.0",
          "description": "Particle Number Concentration from previous size to 5.0um",
          "uuid": "0302d18b-fdff-42c1-9121-a9178e4212c8"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    },
    {
      "sensor": {
        "id": 170,
        "name": "Plantower PMS5003 - PN10.0",
        "description": "Particle Matter PN10.0",
        "unit": "#/0.1l",
        "created_at": "2022-09-08T14:40:39Z",
        "updated_at": "2023-05-23T11:16:20Z",
        "uuid": "9f49fc5a-bab3-43db-b99d-44d3c7086efc",
        "measurement": {
          "id": 45,
          "name": "PN10.0",
          "description": "Particle Number Concentration from previous size to 10.0um",
          "uuid": "f80e84d9-6426-45ab-87e9-3d4cfa61c6d3"
        },
        "tags": [
          "raw"
        ]
      },
      "last_reading_at": "2021-11-29T17:22:01Z"
    }
  ],
  "unauthorized_fields": [
    "device_token",
    "mac_address",
    "data_policy"
  ]
}

@timcowlishaw timcowlishaw marked this pull request as ready for review November 13, 2024 15:58
Future work:
- improve test coverage (on presenters themselves)
- Look into API versioning, use this representation in HTTP API too in a
  new version
- Delete old formatting code once released.
- Sort out the mess of different reading representations we use in
  different places and radically simplify that part of everything
Move shared code into top level application controller, add Devices#show
and Devices#index using new presentations
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant