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

Refactor: remove kits #246

Merged
merged 40 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3fd0944
Refactor to remove kits.
timcowlishaw Jul 5, 2023
5d3bc93
re-add find_component_by_sensor_id to device model
timcowlishaw Nov 23, 2023
76d3560
handshake devices on any mqtt message if necessary
timcowlishaw Nov 27, 2023
b856886
ensure that component keys are unique for their device
timcowlishaw Dec 20, 2023
f569d4d
dont update component updated_at on new reading
timcowlishaw Jan 8, 2024
b976cf3
ensure hardware_info and check jobs dont update device updated_at
timcowlishaw Jan 9, 2024
baa2b9f
add hardware data from kits to devices
timcowlishaw Jan 25, 2024
ea63fba
add hardware to device world map json
timcowlishaw Jan 29, 2024
e1495d1
dont show hardware_info to unauthorized users
timcowlishaw Jan 31, 2024
5debbd4
dont show mac address outside hardware info
timcowlishaw Feb 7, 2024
457a081
location at root of device response
timcowlishaw Feb 26, 2024
4a41bdb
harmonize world map and device view
timcowlishaw Feb 26, 2024
4a2433f
use jbuilder caching instead of action caching
timcowlishaw Feb 28, 2024
e648cf6
dont cache fresh world map
timcowlishaw Feb 28, 2024
9f76182
world map caching properly this time?
timcowlishaw Feb 28, 2024
a26412b
remove hardware description
timcowlishaw Feb 28, 2024
a6b1953
fix Gemfile.lock.
timcowlishaw Feb 28, 2024
70c174d
show mac_address on devices when not null, ensure hardware_name_overr…
timcowlishaw Feb 28, 2024
20c5c35
make hardware info overrides all postable
timcowlishaw Mar 1, 2024
51aca7a
ensure mac addresses for devices are unique
timcowlishaw Mar 1, 2024
22d0add
Revert "ensure mac addresses for devices are unique"
timcowlishaw Mar 7, 2024
afe7132
devices are invalid without a name
timcowlishaw Mar 7, 2024
7afda75
display measurement info within sensor on devices endpoint
timcowlishaw Mar 7, 2024
e2b3fed
group notifications in device response json
timcowlishaw Mar 7, 2024
32bca5d
ensure all sensors which are not ancestors have a default sensor key.…
timcowlishaw Mar 8, 2024
5b1e73f
rename hardware info to last_status_message
timcowlishaw Mar 8, 2024
2e61d2b
sensor tags in device data
timcowlishaw Mar 8, 2024
51a3a98
user emails must be present and unique
timcowlishaw Mar 12, 2024
70d2833
dont 500 on devices endpoint when sensor has no measurement
timcowlishaw Mar 12, 2024
e736331
ensure updating user country code updates computed location data
timcowlishaw Mar 17, 2024
272a4f2
mqtt benchmarking
timcowlishaw Mar 17, 2024
72f3935
tests for unsetting countries etc
timcowlishaw Mar 18, 2024
aa9aa43
add indexes for world map endpoint
timcowlishaw Mar 18, 2024
c0eb0cf
ensure private info not cached in world_map
timcowlishaw Mar 18, 2024
72c9cdb
allow admin access to fresh_world_map
timcowlishaw Mar 18, 2024
3ecd459
ensure delete archived devices job also deletes components
timcowlishaw Mar 18, 2024
1da0bf4
add staging ws configuration
oscgonfer Mar 18, 2024
cfac531
log mqtt client queue length
timcowlishaw Mar 18, 2024
6c00ac4
add better component indices
timcowlishaw Mar 18, 2024
1bdbbb6
staging has a docker volume for cassandra
oscgonfer Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ gem 'doorkeeper', '~> 5'
# To resize active storage images:
# Revise if this is needed after Rails 6.0
gem 'image_processing'

gem 'ancestry'
gem 'api-pagination'
gem 'api_cache'
Expand Down Expand Up @@ -87,6 +86,7 @@ end

group :development, :test do
# gem 'rspec_api_blueprint', require: false
gem "pry"
gem 'brakeman', github: 'presidentbeef/brakeman', require: false
gem 'byebug'
gem 'cane'
Expand Down
3 changes: 2 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ DEPENDENCIES
pg
pg_search
premailer-rails
pry
pry-rails
puma
pundit
Expand Down Expand Up @@ -615,4 +616,4 @@ RUBY VERSION
ruby 3.0.6p216

BUNDLED WITH
2.4.13
2.5.6
1 change: 1 addition & 0 deletions app/controllers/v0/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
include ActionController::Helpers
include ActionController::ImplicitRender
include ActionController::Caching

include Pundit::Authorization
include PrettyJSON
Expand Down
8 changes: 3 additions & 5 deletions app/controllers/v0/components_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@ def index
end

def show
@component = Component.includes(:board, :sensor).find(params[:id])
@component = Component.includes(:device, :sensor).find(params[:id])
authorize @component
end

private

def component_params
params.permit(
:board_id,
:board_type,
:sensor_id,
:equation
:device_id,
:sensor_id
)
end

Expand Down
38 changes: 7 additions & 31 deletions app/controllers/v0/devices_controller.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
module V0
class DevicesController < ApplicationController

before_action :check_if_authorized!, only: [:create]
after_action :verify_authorized,
except: [:index, :world_map, :fresh_world_map]

def show
@device = Device.includes(
:kit, :owner, :sensors,:tags).find(params[:id])
:owner,:tags, {sensors: :measurement}).find(params[:id])
authorize @device
@device
end

def index
raise_ransack_errors_as_bad_request do
@q = policy_scope(Device)
.includes(:owner, :tags, kit: [:components, :sensors])
.includes(:owner, :tags, :components, {sensors: :measurement})
.ransack(params[:q], auth_object: (current_user&.is_admin? ? :admin : nil))

# We are here customly adding multiple tags into the Ransack query.
# Ransack supports this, but how do we add multiple tag names in URL string? Which separator to use?
# See Issue #186 https://github.com/fablabbcn/smartcitizen-api/issues/186
Expand Down Expand Up @@ -75,36 +75,9 @@ def destroy

# debug method, must be refactored
def fresh_world_map
@devices = Device.where.not(latitude: nil).where.not(data: nil).includes(:owner,:tags).map do |device|
{
id: device.id,
name: device.name,
description: (device.description.present? ? device.description : nil),
owner_id: device.owner_id,
owner_username: device.owner_id ? device.owner_username : nil,
latitude: device.latitude,
longitude: device.longitude,
city: device.city,
country_code: device.country_code,
is_private: device.is_private,
kit_id: device.kit_id,
state: device.state,
system_tags: device.system_tags,
user_tags: device.user_tags,
added_at: device.added_at,
updated_at: device.updated_at,
last_reading_at: (device.last_reading_at.present? ? device.last_reading_at : nil)
}
end
render json: @devices
end

def world_map
unless params[:cachebuster]
expires_in 30.seconds, public: true # CRON cURL every 60 seconds to cache
end

render json: Device.for_world_map
end

private
Expand All @@ -113,6 +86,10 @@ def device_params
params_to_permit = [
:name,
:description,
:hardware_name_override,
:hardware_version_override,
:hardware_type_override,
:hardware_slug_override,
:mac_address,
:latitude,
:longitude,
Expand All @@ -122,7 +99,6 @@ def device_params
:notify_stopped_publishing,
:exposure,
:meta,
:kit_id,
:user_tags,
postprocessing_attributes: [:blueprint_url, :hardware_url, :latest_postprocessing, :meta, :forwarding_params],
]
Expand Down
48 changes: 0 additions & 48 deletions app/controllers/v0/kits_controller.rb

This file was deleted.

2 changes: 1 addition & 1 deletion app/controllers/v0/onboarding/orphan_devices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def update
private

def orphan_device_params
params.permit(:name, :description, :kit_id, :exposure, :latitude, :longitude, :user_tags)
params.permit(:name, :description, :exposure, :latitude, :longitude, :user_tags)
end

def set_orphan_device
Expand Down
5 changes: 0 additions & 5 deletions app/controllers/v0/readings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ def csv_archive
@device = Device.find(params[:id])
authorize @device, :update?

if @device.kit.nil?
render json: { id: "error", message: "Device does not have a kit", url: "", errors: "" }, status: 420
return
end

if [email protected]_export_requested_at or (@device.csv_export_requested_at < 15.minutes.ago)
@device.update_column(:csv_export_requested_at, Time.now.utc)
if Rails.env.test?
Expand Down
13 changes: 6 additions & 7 deletions app/controllers/v0/static_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ def home
current_user_url: [request.base_url, v0_me_index_path].join,
components_url: [request.base_url, v0_components_path].join,
devices_url: [request.base_url, v0_devices_path].join,
kits_url: [request.base_url, v0_kits_path].join,
measurements_url: [request.base_url, v0_measurements_path].join,
sensors_url: [request.base_url, v0_sensors_path].join,
users_url: [request.base_url, v0_users_path].join,
Expand All @@ -32,12 +31,12 @@ def metrics
private: Device.where(is_private: true).count,
test: Device.where(is_test: true).count,
online: {
now: Device.where('last_recorded_at > ?', 10.minutes.ago).count,
last_hour: Device.where('last_recorded_at > ?', 1.hour.ago).count,
today: Device.where('last_recorded_at > ?', Time.now.beginning_of_day).count,
this_month: Device.where('last_recorded_at > ?', Time.now.beginning_of_month).count,
this_year: Device.where('last_recorded_at > ?', Time.now.beginning_of_year).count,
all_time: Device.where.not(last_recorded_at: nil).count
now: Device.where('last_reading_at > ?', 10.minutes.ago).count,
last_hour: Device.where('last_reading_at > ?', 1.hour.ago).count,
today: Device.where('last_reading_at > ?', Time.now.beginning_of_day).count,
this_month: Device.where('last_reading_at > ?', Time.now.beginning_of_month).count,
this_year: Device.where('last_reading_at > ?', Time.now.beginning_of_year).count,
all_time: Device.where.not(last_reading_at: nil).count
},
readings: {
good: {
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/check_battery_level_below_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def perform(*args)
if device.data["10"].to_i < 15 && device.data["10"].to_i > 1
#p "Sending email to: #{device.owner.email} - device: #{device}"

device.update(notify_low_battery_timestamp: Time.now)
device.update_column(:notify_low_battery_timestamp, Time.now)

UserMailer.device_battery_low(device.id).deliver_now
end
Expand Down
4 changes: 2 additions & 2 deletions app/jobs/check_device_stopped_publishing_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ class CheckDeviceStoppedPublishingJob < ApplicationJob
def perform(*args)
# Do something later

devices = Device.where(notify_stopped_publishing: true).where("last_recorded_at < ?", 60.minutes.ago)
devices = Device.where(notify_stopped_publishing: true).where("last_reading_at < ?", 60.minutes.ago)
CheckupNotifyJob.perform_now("#{devices.count} devices with notification on: stopped_publishing at least an hour ago. Ids: #{devices.pluck(:id)}")

devices.each do |device|
if device.notify_stopped_publishing_timestamp < 24.hours.ago
device.update notify_stopped_publishing_timestamp: Time.now
device.update_column(:notify_stopped_publishing_timestamp, Time.now)
UserMailer.device_stopped_publishing(device.id).deliver_now
end
end
Expand Down
22 changes: 11 additions & 11 deletions app/lib/mqtt_messages_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ def self.handle_topic(topic, message)

return if topic.nil?

handshake_device(topic)

# The following do NOT need a device
if topic.to_s.include?('inventory')
DeviceInventory.create({ report: (message rescue nil) })
elsif topic.to_s.include?('hello')
orphan_device = OrphanDevice.find_by(device_token: device_token(topic))
return if orphan_device.nil?

handle_hello(orphan_device)
end

device = Device.find_by(device_token: device_token(topic))
Expand All @@ -41,7 +38,7 @@ def self.handle_topic(topic, message)
}
)
Sentry.add_breadcrumb(crumb)
device.update hardware_info: json_message
device.update_column(:hardware_info, json_message)
end
end

Expand All @@ -55,6 +52,7 @@ def self.handle_readings(device, message)
end
rescue Exception => e
Sentry.capture_exception(e)
raise e if Rails.env.test?
#puts e.inspect
#puts message
end
Expand Down Expand Up @@ -88,11 +86,13 @@ def self.parse_raw_readings(message, device_id=nil)
JSON[reading]
end

def self.handle_hello(orphan_device)
payload = {}
orphan_device.update(device_handshake: true)
payload[:onboarding_session] = orphan_device.onboarding_session
Redis.current.publish('token-received', payload.to_json)
def self.handshake_device(topic)
orphan_device = OrphanDevice.find_by(device_token: device_token(topic))
return if orphan_device.nil?
orphan_device.update!(device_handshake: true)
Redis.current.publish('token-received', {
onboarding_session: orphan_device.onboarding_session
}.to_json)
end

# takes a packet and returns 'device token' from topic
Expand Down
26 changes: 23 additions & 3 deletions app/models/component.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# This joins a device with its sensors.

class Component < ActiveRecord::Base
belongs_to :board, polymorphic: true
belongs_to :device
belongs_to :sensor

validates_presence_of :board, :sensor
validates :sensor_id, :uniqueness => { :scope => [:board_id, :board_type] }
validates_presence_of :device, :sensor
validates :sensor_id, :uniqueness => { :scope => [:device_id] }
validates :key, :uniqueness => { :scope => [:device_id] }

before_validation :set_key, on: :create

delegate :equation, :reverse_equation, to: :sensor

# Accepts a raw sensor reading and uses its equation to process and return
# a calibrated version
Expand All @@ -19,4 +24,19 @@ def normalized_value x
reverse_equation ? eval( ['->x{',reverse_equation,'}'].join ).call(x) : x
end

def get_unique_key(default_key, other_keys)
matching_keys = other_keys.select { |k| k =~ /^#{default_key}/ }
ix = matching_keys.length
ix == 0 ? default_key : "#{default_key}_#{ix}"
end

private

def set_key
if sensor && device && !key
default_key = sensor.default_key
other_component_keys = device.components.map(&:key)
self.key = get_unique_key(default_key, other_component_keys)
end
end
end
16 changes: 3 additions & 13 deletions app/models/concerns/data_parser/storer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,12 @@ def timestamp_parse(timestamp)
end

def sensor_reading(device, sensor)
begin
id = Integer(sensor['id'])
key = device.find_sensor_key_by_id(id)
rescue
key = sensor['id']
id = device.find_sensor_id_by_key(key)
end
component = device.components.detect{ |c| c["sensor_id"] == id }

#raise "This component does not have sensor_id: #{id}" if component.nil?
component = device.find_or_create_component_for_sensor_reading(sensor)
return nil if component.nil?

value = component.normalized_value( (Float(sensor['value']) rescue sensor['value']) )
{
id: id,
key: key,
id: component.sensor_id,
key: component.key,
component: component,
value: value
}
Expand Down
Loading
Loading