Skip to content

Commit

Permalink
add hardware data from kits to devices
Browse files Browse the repository at this point in the history
  • Loading branch information
timcowlishaw committed Jan 25, 2024
1 parent acccc20 commit 906f0ff
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 5 deletions.
31 changes: 31 additions & 0 deletions app/models/device.rb
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,37 @@ def update_component_timestamps(timestamp, sensor_ids)
end
end

def hardware
{
name: hardware_name,
type: hardware_type,
description: hardware_description,
version: hardware_version,
slug: hardware_slug,
info: hardware_info,
}
end

def hardware_name
hardware_name_override || [hardware_version ? "SmartCitizen Kit" : "Unknown", hardware_version].compact.join(" ")
end

def hardware_type
hardware_type_override || (hardware_version ? "SCK" : "Unknown")
end

def hardware_description
hardware_description_override || hardware_name
end

def hardware_version
hardware_version_override || hardware_info&.fetch('hw_ver', nil)
end

def hardware_slug
hardware_slug_override || [hardware_type.downcase, hardware_version&.gsub(".", ",")].compact.join(":")
end

private

def set_state
Expand Down
2 changes: 1 addition & 1 deletion app/views/v0/devices/_device.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ json.(
:description,
:state,
:postprocessing,
:hardware_info,
:system_tags,
:user_tags,
:is_private,
:notify_low_battery,
:notify_stopped_publishing,
:last_reading_at,
:hardware,
:created_at,
:updated_at
)
Expand Down
46 changes: 46 additions & 0 deletions db/data/kits.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
id,name,description,slug,hardware_type,hardware_name,hardware_version,hardware_description,hardware_slug
2,SmartCitizen Kit 1.0,SCK 1.0 - Ambient Board,"sck:1,0",SCK,SmartCitizen Kit 1.0,1.0,SCK 1.0 - Ambient Board,
3,SmartCitizen Kit 1.1,SCK 1.1 - Ambient Board,"sck:1,1",SCK,SmartCitizen Kit 1.1,1.1,SCK 1.1 - Ambient Board,
4,NO2 Diffusion Tubes,Nitrogen Oxides Diffusion Tubes Spreadsheet,"ms:0,5",MS,NO2 Diffusion Tubes,0.5,Nitrogen Oxides Diffusion Tubes Spreadsheet,
5,Noise Sensor TA120,Noise Sensor CESVA TA120,"ms:0,6",CESVA,Noise Sensor TA120,TA210,Noise Sensor CESVA TA120,
6,Processing Open CV,Open CV based sensor running built on Processing.org and running on a Raspberry Pi,"ms:0,3",MS,Processing Open CV,0.3,Open CV based sensor running built on Processing.org and running on a Raspberry Pi,
7,Smart Citizen Kit 1.5 Expanded,SCK 1.5 + Grove Analog Sensor,"ms:0,4",SCK,Smart Citizen Kit 1.5 Expanded,1.5,SCK 1.5 + Grove Analog Sensor,
8,Making Sense WAAG #1,AQM sensor by WAAG,"ms:1,0",MS,Making Sense WAAG #1,1.0,AQM sensor by WAAG,
9,Making Sense WAAG #2,AQM sensor by WAAG 2,"ms:1,1",MS,Making Sense WAAG #2,1.0,AQM sensor by WAAG 2,
10,Making Sense WAAG #3,AQM sensor by WAAG 3,"ms:1,3",MS,Making Sense WAAG #3,1.0,AQM sensor by WAAG 3,
11,SCK 1.5 MS,SCK 1.5 - MS Pilot,"sck:1,5",SCK,SCK 1.5 MS,1.5,SCK 1.5 - MS Pilot,
12,Bora Kit,Bora Air Quality Sensors Kit,"ms:2,0",BK,Bora Kit,1.0,Bora Air Quality Sensors Kit,
13,GammaSense Kit,GammaSense web app that uses device camera via WebRTC,"ms:3,0",GSK,GammaSense Kit,1.0,GammaSense web app that uses device camera via WebRTC,
14,SCK 1.5,SCK 1.5 - Urban Board,"sck:1,5,1",SCK,SCK 1.5,1.5,SCK 1.5 - Urban Board,
15,SCK Aquapioneers 1.5 ,SCK 1.5 - Urban Board + Aquapioneers Board ,"sck:1,5:aq",SCK,SCK Aquapioneers 1.5 ,1.5,SCK 1.5 - Urban Board + Aquapioneers Board ,
16,SCK Grow Soil Probes,SCK 1.5 + Atlas Scientific Sensor Probes,"sck:1,5:grow:as",SCK,SCK Grow Soil Probes,1.5,SCK 1.5 + Atlas Scientific Sensor Probes,
17,SCK Grow Soil Moisture,SCK 1.5 + Urban Board + Chirp Moisture Sensor,"sck:1,5:grow:moisture",SCK,SCK Grow Soil Moisture,1.5,SCK 1.5 + Urban Board + Chirp Moisture Sensor,
18,SCK 2.0 - Dev,SCK 2.0 - Urban Board - Dev,"sck:2,0,1:dev",SCK,SCK 2.0 - Dev,2.0,SCK 2.0 - Urban Board - Dev,
19,iSCAPE Station - Dev,iSCAPE Stations Development Kit,"sck:2,0:dev:iscape:station",SCK,iSCAPE Station - Dev,2.0,iSCAPE Stations Development Kit,
20,iSCAPE Citizen Kit,iSCAPE Citizen Kit ,"sck:2,0,1",SCK,iSCAPE Citizen Kit,2.0,iSCAPE Citizen Kit ,
21,iSCAPE Station,iSCAPE Living Labs Station,"sck:2,0:iscape:station",SCK,iSCAPE Station,2.0,iSCAPE Living Labs Station,
22,BioPV Kit,SCK 2.0 - Urban Board + Atlas Scientific Sensors + Chirp Moisture + ADC,"sck:1,5:biopv",SCK,BioPV Kit,2.0,SCK 2.0 - Urban Board + Atlas Scientific Sensors + Chirp Moisture + ADC,
23,SCK Aquapioneers Lite 1.5,SCK 1.5 - Aquapioneers Lite Board ,"sck:1,5:aq:lite",SCK,SCK Aquapioneers Lite 1.5,1.5,SCK 1.5 - Aquapioneers Lite Board ,
24,SCK Wine Makers,SCK 2.0 + Waterproof Temperature Sensor,"sck:2,0:winemakers",SCK,SCK Wine Makers,2.0,SCK 2.0 + Waterproof Temperature Sensor,
25,SCK 2.1 for DECODE,DECODE Citizen Kit ,"sck:2,0,1:decode",SCK,SCK 2.1 for DECODE,2.1,DECODE Citizen Kit ,
26,SCK 2.1,Smart Citizen Kit 2.1 with Urban Sensor Board,"sck:2,1",SCK,SCK 2.1,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board,
27,SCK Grow Soil Moisture 2.1,Smart Citizen Kit 2.1 with Urban Sensor Board and Chirp Soil Moisture,"sck:2,1:grow:moisture",SCK,SCK Grow Soil Moisture 2.1,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board and Chirp Soil Moisture,
28,iSCAPE Station 2.1,iSCAPE Living Labs Station 2.1,"sck:2,1:iscape:station",SCK,iSCAPE Station 2.1,2.1,iSCAPE Living Labs Station 2.1,
29,SCK 2.1 Formaldehyde,Smart Citizen Kit 2.1 with Urban Sensor Board with Formaldehyde,"sck:2,1:form",SCK,SCK 2.1 Formaldehyde,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board with Formaldehyde,
30,SCK 2.1 PM Board Addons,Smart Citizen Kit 2.1 with PM Board for Experimental I/O,"sck:2,1:pmboard:experiments",SCK,SCK 2.1 PM Board Addons,2.1,Smart Citizen Kit 2.1 with PM Board for Experimental I/O,
31,SCK 2.1 Sea Water,Smart Citizen Kit 2.1 with Sea Water Sensors,"sck:2,1:seawater",SCK,SCK 2.1 Sea Water,2.1,Smart Citizen Kit 2.1 with Sea Water Sensors,
32,SCK 2.1 GPS,Smart Citizen Kit 2.1 with GPS,"sck:2,1:gps",SCK,SCK 2.1 GPS,2.1,Smart Citizen Kit 2.1 with GPS,
33,Smart Citizen Station 2.1 rev3,Smart Citizen Station 2.1 rev3,"sck:2,1:station:rev3",SCK,Smart Citizen Station 2.1 rev3,2.1,Smart Citizen Station 2.1 rev3,
34,BioPV Kit 2.1,SCK 2.1 - Urban Board + PM + Atlas + Soil Moisture + ADC ADS1115,"sck:2,1:biopv",SCK,BioPV Kit 2.1,2.1,SCK 2.1 - Urban Board + PM + Atlas + Soil Moisture + ADC ADS1115,
35,SCK 2.1 CO2,SCK 2.1 - Urban Board + PM + CO2,"sck:2,1:co2",SCK,SCK 2.1 CO2,2.1,SCK 2.1 - Urban Board + PM + CO2,
36,"SCK 2.1 CO2, CO and NO2",SCK 2.1 - Urban Board + PM + CO2 + CO + NO2,"sck:2,1:co2:co:no2",SCK,"SCK 2.1 CO2, CO and NO2",2.1,SCK 2.1 - Urban Board + PM + CO2 + CO + NO2,
37,"SCK 2.1 NO2, O3",SCK 2.1 - Urban Board + PM + NO2 + O3,"sck:2,1:no2:o3",SCK,"SCK 2.1 NO2, O3",2.1,SCK 2.1 - Urban Board + PM + NO2 + O3,
38,SCK 2.1 Soil and Air,"SCK 2.1 - Soil Moisture, Soil Temperature and Air","sck:2,1:soil:air",SCK,SCK 2.1 Soil and Air,2.1,"SCK 2.1 - Soil Moisture, Soil Temperature and Air",
39,SCK 2.1 T/RH,SCK 2.1 - Urban Board + PM + T + RH,"sck:2,1:t:rh",SCK,SCK 2.1 T/RH,2.1,SCK 2.1 - Urban Board + PM + T + RH,
40,DIY Sensor Kit PCTO @ LD22,"DIY Sensor Kit PCTO for air quality, environment and GPS readings",dyi:pm:co2:gps,DIY,DIY Sensor Kit PCTO @ LD22,1.0,"DIY Sensor Kit PCTO for air quality, environment and GPS readings",
41,SCK 2.1 SPS30,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SPS30,"sck:2,1",SCK,SCK 2.1 SPS30,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SPS30,
42,SCK 2.1 SEN5X,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SEN5X,"sck:2,1",SCK,SCK 2.1 SEN5X,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SEN5X,
43,SCK 2.1 SFA30,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SFA30,"sck:2,1",SCK,SCK 2.1 SFA30,2.1,Smart Citizen Kit 2.1 with Urban Sensor Board and Sensirion SFA30,
44,SCK 2.1 SFA30 and SCD30,"Smart Citizen Kit 2.1 with Urban Sensor Board, Sensirion SCD30 and Sensirion SFA30","sck:2,1",SCK,SCK 2.1 SFA30 and SCD30,2.1,"Smart Citizen Kit 2.1 with Urban Sensor Board, Sensirion SCD30 and Sensirion SFA30",
45,SCK 2.1 Debug,Smart Citizen Kit 2.1 internal development,"sck:2,1",SCK,SCK 2.1 Debug,2.1,Smart Citizen Kit 2.1 internal development,
,,,,,,,,
54 changes: 52 additions & 2 deletions db/migrate/20230704150532_refactor_kits.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'csv'
class RefactorKits < ActiveRecord::Migration[6.0]

def execute(query, args=[])
Expand Down Expand Up @@ -35,6 +36,14 @@ def change
t.column :reverse_equation, :string, null: true
end

change_table :devices do |t|
t.column :hardware_type_override, :string, null: true
t.column :hardware_name_override, :string, null: true
t.column :hardware_version_override, :string, null: true
t.column :hardware_description_override, :string, null: true
t.column :hardware_slug_override, :string, null: true
end

# Add default key to sensors to be used when new components are created:
puts "-- setting default keys for sensors"

Expand Down Expand Up @@ -82,12 +91,53 @@ def change
end
end

# For each existing device. Look up its kit, and create a component for each of that kit's components, with reference to the device itself.
# For each existing device. Look up its kit, set its hardware_info, and create a component for each of that kit's components, with reference to the device itself.

puts "-- creating device components"
kits_info = CSV.foreach("db/data/kits.csv", headers:true).map(&:to_h).reduce({}) { |h, r| h[r["id"].to_i] = r; h }


puts "-- setting hardware info and creating components for devices"

execute("SELECT * FROM devices").each do |device_row|
execute("SELECT * FROM kits WHERE id = ? LIMIT 1", device_row["kit_id"]).each do |kit_row|

device_id = device_row["id"]

kit_id = kit_row["id"]
kit_info = kits_info[kit_id]

hardware_version = kit_info["hardware_version"]

unless kit_info["hardware_type"] == "SCK"
hardware_type = kit_info["hardware_type"]
end

default_name = "SmartCitizen Kit #{hardware_version}"
unless kit_info["hardware_name"] == default_name
hardware_name = kit_info["hardware_name"]
end

default_slug = "#{kit_info["hardware_type"].downcase}:#{hardware_version.gsub(".", ",")}"
unless kit_info["slug"] == default_slug
hardware_slug = kit_info["slug"]
end

unless kit_info["hardware_description"] == kit_info["hardware_name"]
hardware_description = kit_info["hardware_description"]
end

execute("""
UPDATE devices
SET
hardware_version_override = ?,
hardware_type_override = ?,
hardware_name_override = ?,
hardware_description_override = ?,
hardware_slug_override = ?
WHERE id = ?
""", [hardware_version, hardware_type, hardware_name, hardware_description, hardware_slug, device_id])


kit_component_rows = execute("""
SELECT * FROM components
WHERE board_type = 'Kit'
Expand Down
5 changes: 5 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@
t.boolean "is_private", default: false
t.boolean "is_test", default: false, null: false
t.datetime "archived_at"
t.string "hardware_type_override"
t.string "hardware_name_override"
t.string "hardware_version_override"
t.string "hardware_description_override"
t.string "hardware_slug_override"
t.index ["device_token"], name: "index_devices_on_device_token", unique: true
t.index ["geohash"], name: "index_devices_on_geohash"
t.index ["last_reading_at"], name: "index_devices_on_last_reading_at"
Expand Down
115 changes: 115 additions & 0 deletions spec/models/device_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,121 @@
end
end

describe "hardware info" do
describe "hardware_name" do
context "when it has a name override" do
it "returns the overriden name" do
device = create(:device, hardware_name_override: "Overriden name")
expect(device.hardware_name).to eq("Overriden name")
end
end

context "when it has a hardware_version" do
it "returns the string 'SmartCitizen Kit' concatenated with the version" do
device = create(:device)
expect(device).to receive(:hardware_version).at_least(:once).and_return("1.0.0")
expect(device.hardware_name).to eq("SmartCitizen Kit 1.0.0")
end
end

context "otherwise" do
it "returns the string 'Unknown'" do
device = create(:device)
expect(device.hardware_name).to eq("Unknown")
end
end
end

describe "hardware_type" do
context "when it has a type override" do
it "returns the overriden type" do
device = create(:device, hardware_type_override: "Overriden type")
expect(device.hardware_type).to eq("Overriden type")
end
end

context "when it has a hardware_version" do
it "returns the string 'SCK'" do
expect(device).to receive(:hardware_version).and_return("1.0.0")
expect(device.hardware_type).to eq("SCK")
end
end

context "otherwise" do
it "returns the string 'Unknown'" do
device = create(:device)
expect(device.hardware_type).to eq("Unknown")
end
end
end

describe "hardware_version" do
context "when it has a version override" do
it "returns the overriden version" do
device = create(:device, hardware_version_override: "1.4.0+with+extra+sensors")
expect(device.hardware_version).to eq("1.4.0+with+extra+sensors")
end
end

context "when it has hardware_info" do
it "returns the version from hardware_info" do
device = create(:device, hardware_info: { hw_ver: "1.5.0" })
expect(device.hardware_version).to eq("1.5.0")
end
end

context "otherwise" do
it "returns nil" do
device = create(:device)
expect(device.hardware_version).to be(nil)
end
end
end

describe "hardware_description" do
context "when it has a description override" do
it "returns the overriden description" do
device = create(:device, hardware_description_override: "Overriden description")
expect(device.hardware_description).to eq("Overriden description")
end
end

context "otherwise" do
it "returns the hardware_name" do
device = create(:device)
expect(device).to receive(:hardware_name).and_return("Hardware name")
expect(device.hardware_description).to eq("Hardware name")
end

end
end

describe "hardware_slug" do
context "when it has a slug override" do
it "returns the overriden slug" do
device = create(:device, hardware_slug_override: "overriden_slug")
expect(device.hardware_slug).to eq("overriden_slug")
end
end

context "when it has a hardware_version" do
it "returns the hardware type downcased, concatenated with the version number with periods translated to commas, seperated by a colon" do
device = create(:device)
expect(device).to receive(:hardware_type).and_return("SCK")
expect(device).to receive(:hardware_version).and_return("1.0.0")
expect(device.hardware_slug).to eq("sck:1,0,0")
end
end

context "when it has no harware version" do
it "returns the hardware type downcased" do
device = create(:device)
expect(device.hardware_slug).to eq("unknown")
end
end
end
end

describe "#find_or_create_component_by_sensor_id" do
context "when the sensor exists and a component already exists for this device" do
it "returns the existing component" do
Expand Down
3 changes: 1 addition & 2 deletions spec/requests/v0/devices_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
expect(json.length).to eq(2)
# expect(json[0]['name']).to eq(first.name)
# expect(json[1]['name']).to eq(second.name)
expect(json[0].keys).to eq(%w(id uuid name description state postprocessing
hardware_info system_tags user_tags is_private notify_low_battery notify_stopped_publishing last_reading_at created_at updated_at mac_address device_token owner data))
expect(json[0].keys).to eq(%w(id uuid name description state postprocessing system_tags user_tags is_private notify_low_battery notify_stopped_publishing last_reading_at hardware created_at updated_at mac_address device_token owner data))
end

describe "when not logged in" do
Expand Down

0 comments on commit 906f0ff

Please sign in to comment.