Merge pull request #1177 from RickCarlino/account_seeder_iii

Account seeders for Express models
pull/1179/head
Rick Carlino 2019-05-02 15:17:03 -05:00 committed by GitHub
commit 18ae05ca82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 332 additions and 98 deletions

View File

@ -9,6 +9,7 @@ class FbosConfig < ApplicationRecord
ARDUINO = "arduino",
FARMDUINO = "farmduino",
FARMDUINO_K14 = "farmduino_k14",
EXPRESS_V10 = "express_v10"
]
NERVES_FIELD = "update_channel"

View File

@ -0,0 +1,98 @@
module Devices
module Seeders
class AbstractExpress < AbstractGenesis
def settings_device_name
device.update_attributes!(name: "FarmBot Express")
end
def sensors_soil_sensor; end
def sensors_tool_verification; end
def settings_enable_encoders
device.firmware_config.update_attributes!(encoder_enabled_x: 0,
encoder_enabled_y: 0,
encoder_enabled_z: 0)
end
def settings_firmware
device
.fbos_config
.update_attributes!(firmware_hardware: FbosConfig::EXPRESS_V10)
end
def tool_slots_slot_1
add_tool_slot(ToolNames::SEED_TROUGH_1,
0,
25,
-200,
ToolSlot::NONE,
true)
end
def tool_slots_slot_2
add_tool_slot(ToolNames::SEED_TROUGH_2,
0,
50,
-200,
ToolSlot::NONE,
true)
end
def tool_slots_slot_3
add_tool_slot(ToolNames::SEED_TROUGH_3,
0,
75,
-200,
ToolSlot::NONE,
true)
end
def tool_slots_slot_4; end
def tool_slots_slot_5; end
def tool_slots_slot_6; end
def tools_seed_bin; end
def tools_seed_tray; end
def tools_seed_trough_1
add_tool(ToolNames::SEED_TROUGH_1)
end
def tools_seed_trough_2
add_tool(ToolNames::SEED_TROUGH_2)
end
def tools_seed_trough_3
add_tool(ToolNames::SEED_TROUGH_3)
end
def tools_seeder; end
def tools_soil_sensor; end
def tools_watering_nozzle; end
def tools_weeder; end
def sequences_mount_tool; end
def sequences_pick_up_seed
s = SequenceSeeds::PICK_UP_SEED_EXPRESS.deep_dup
s.dig(:body, 1, :args, :location, :args)[:tool_id] = seed_trough_1_id
s.dig(:body, 2, :args, :pin_number, :args)[:pin_id] = vacuum_id
s.dig(:body, 3, :args, :location, :args)[:tool_id] = seed_trough_1_id
s.dig(:body, 4, :args, :location, :args)[:tool_id] = seed_trough_1_id
Sequences::Create.run!(s, device: device)
end
def sequences_tool_error; end
def sequences_unmount_tool; end
def settings_default_map_size_y
device.web_app_config.update_attributes!(map_size_y: 1_200)
end
private
def seed_trough_1_id
@seed_trough_1_id ||= device.tools.find_by!(name: ToolNames::SEED_TROUGH_1).id
end
end
end
end

View File

@ -1,15 +1,6 @@
module Devices
module Seeders
class AbstractGenesis < AbstractSeeder
PRODUCT_LINE = Devices::Seeders::Constants::ProductLines::GENESIS
SEQUENCES_MOUNT_TOOL = true
SEQUENCES_PICKUP_SEED = true
SEQUENCES_PLANT_SEED = true
SEQUENCES_TAKE_PHOTO_OF_PLANT = true
SEQUENCES_TOOL_ERROR = true
SEQUENCES_UNMOUNT_TOOL = true
SEQUENCES_WATER_PLANT = true
def peripherals_vacuum
add_peripheral(9, ToolNames::VACUUM)
end
@ -106,7 +97,6 @@ module Devices
end
def sequences_pick_up_seed
return unless self.class::SEQUENCES_PICKUP_SEED
s = SequenceSeeds::PICK_UP_SEED_GENESIS.deep_dup
seed_bin_id = device.tools.find_by!(name: ToolNames::SEED_BIN).id

View File

@ -4,19 +4,6 @@ module Devices
include Constants
attr_reader :device
PRODUCT_LINE = ProductLines::NONE
# Class level configuration.
# Change these values on child class to tune
# default sequences.
SEQUENCES_MOUNT_TOOL = false
SEQUENCES_PICKUP_SEED = false
SEQUENCES_PLANT_SEED = false
SEQUENCES_TAKE_PHOTO_OF_PLANT = false
SEQUENCES_TOOL_ERROR = false
SEQUENCES_UNMOUNT_TOOL = false
SEQUENCES_WATER_PLANT = false
# DO NOT ALPHABETIZE. ORDER MATTERS! - RC
COMMAND_ORDER = [
# PLANTS =================================
@ -105,19 +92,10 @@ module Devices
def pin_bindings_button_2; end
def sensors_soil_sensor; end
def sensors_tool_verification; end
def sequences_mount_tool
return unless self.class::SEQUENCES_MOUNT_TOOL
# TODO: Implement me...
end
def sequences_pick_up_seed
return unless self.class::SEQUENCES_PICKUP_SEED
# TODO: Implement me...
end
def sequences_mount_tool; end
def sequences_pick_up_seed; end
def sequences_plant_seed
return unless self.class::SEQUENCES_PLANT_SEED
s = SequenceSeeds::PLANT_SEED.deep_dup
s.dig(:body, 2, :args, :pin_number, :args)[:pin_id] = vacuum_id
@ -125,18 +103,15 @@ module Devices
end
def sequences_take_photo_of_plant
return unless self.class::SEQUENCES_TAKE_PHOTO_OF_PLANT
s = SequenceSeeds::TAKE_PHOTO_OF_PLANT.deep_dup
Sequences::Create.run!(s, device: device)
end
def sequences_tool_error
return unless self.class::SEQUENCES_TOOL_ERROR
Sequences::Create.run!(SequenceSeeds::TOOL_ERROR, device: device)
end
def sequences_unmount_tool
return unless self.class::SEQUENCES_UNMOUNT_TOOL
s = SequenceSeeds::UNMOUNT_TOOL.deep_dup
s.dig(:args,
@ -146,7 +121,6 @@ module Devices
:args,
:default_value,
:args)[:tool_id] = seeder_id
s.dig(:body, 5, :args, :pin_number, :args)[:pin_id] = tool_verification_id
s.dig(:body, 6, :args, :lhs, :args)[:pin_id] = tool_verification_id
s.dig(:body, 6, :args, :_else, :args)[:sequence_id] = tool_error_id
@ -154,7 +128,6 @@ module Devices
end
def sequences_water_plant
return unless self.class::SEQUENCES_WATER_PLANT
s = SequenceSeeds::WATER_PLANT.deep_dup
s.dig(:body, 1, :args, :pin_number, :args)[:pin_id] = water_id
@ -170,9 +143,7 @@ module Devices
device.update_attributes!(name: "FarmBot Genesis")
end
def settings_enable_encoders
# TODO
end
def settings_enable_encoders; end
def settings_firmware; end
@ -254,13 +225,19 @@ module Devices
mode: mode)
end
def add_tool_slot(name, x, y, z, pullout_direction = ToolSlot::POSITIVE_X)
def add_tool_slot(name,
x,
y,
z,
pullout_direction = ToolSlot::POSITIVE_X,
gantry_mounted = false)
Points::Create.run!(pointer_type: "ToolSlot",
name: name,
x: x,
y: y,
z: z,
pullout_direction: pullout_direction,
gantry_mounted: gantry_mounted,
device: device)
end

View File

@ -29,6 +29,9 @@ module Devices
WATERING_NOZZLE = "Watering Nozzle"
WEEDER = "Weeder"
LIGHTING = "Lighting"
SEED_TROUGH_1 = "Seed Trough 1"
SEED_TROUGH_2 = "Seed Trough 2"
SEED_TROUGH_3 = "Seed Trough 3"
end
# Stub plants ==============================

View File

@ -1,6 +1,6 @@
module Devices
module Seeders
class ExpressOneZero < AbstractSeeder
class ExpressOneZero < AbstractExpress
end
end
end

View File

@ -1,6 +1,17 @@
module Devices
module Seeders
class ExpressXlOneZero < AbstractSeeder
class ExpressXlOneZero < AbstractExpress
def settings_device_name
device.update_attributes!(name: "FarmBot Express XL")
end
def settings_default_map_size_x
device.web_app_config.update_attributes!(map_size_x: 6_000)
end
def settings_default_map_size_y
device.web_app_config.update_attributes!(map_size_y: 2_400)
end
end
end
end

View File

@ -1,13 +1,7 @@
module Devices
module Seeders
class None < AbstractSeeder
SEQUENCES_PICKUP_SEED = ProductLines::NONE
SEQUENCES_MOUNT_TOOL = false
SEQUENCES_PLANT_SEED = false
SEQUENCES_TAKE_PHOTO_OF_PLANT = false
SEQUENCES_TOOL_ERROR = false
SEQUENCES_UNMOUNT_TOOL = false
SEQUENCES_WATER_PLANT = false
def sequences_unmount_tool; end
end
end
end

View File

@ -1,6 +1,17 @@
module Devices
module Seeders
class XlOneFour < AbstractGenesis
def settings_default_map_size_x
device.web_app_config.update_attributes!(map_size_x: 6_000)
end
def settings_default_map_size_y
device.web_app_config.update_attributes!(map_size_y: 3_000)
end
def settings_device_name
device.update_attributes!(name: "FarmBot Genesis XL")
end
end
end
end

View File

@ -18,43 +18,44 @@ module Points
# Smaller bed = higher resolution.
POINT_HARD_LIMIT = 1000 # Can't exceed this.
POINT_SOFT_LIMIT = (POINT_HARD_LIMIT * 0.8).to_i
BAD_TOOL_ID = "Can't find tool with id %s"
DEFAULT_NAME = "Untitled %s"
KINDS = Point::POINTER_KINDS
GETTING_CLOSE = "Your account is "\
"approaching the allowed point limit of "\
"#{POINT_HARD_LIMIT}. Consider deleting old"\
" points to avoid adverse performance."
TOO_MANY = "Your device has hit the "\
"max limit for point usage (currently "\
"#{POINT_HARD_LIMIT}). Please delete unused"\
" map points and plants to create more "
BAD_POINTER_TYPE = \
"Please provide a JSON object with a `poin"\
"ter_type` that matches one of the followi"\
BAD_TOOL_ID = "Can't find tool with id %s"
DEFAULT_NAME = "Untitled %s"
KINDS = Point::POINTER_KINDS
GETTING_CLOSE = "Your account is " \
"approaching the allowed point limit of " \
"#{POINT_HARD_LIMIT}. Consider deleting old" \
" points to avoid adverse performance."
TOO_MANY = "Your device has hit the " \
"max limit for point usage (currently " \
"#{POINT_HARD_LIMIT}). Please delete unused" \
" map points and plants to create more "
BAD_POINTER_TYPE =
"Please provide a JSON object with a `poin" \
"ter_type` that matches one of the followi" \
"ng values: #{KINDS.join(", ")}"
required do
float :x
float :y
float :z, default: 0
model :device, class: Device
float :x
float :y
float :z, default: 0
model :device, class: Device
string :pointer_type
end
optional do
hstore :meta
float :radius, default: 25
float :radius, default: 25
integer :pullout_direction,
min: ToolSlot::PULLOUT_DIRECTIONS.min,
max: ToolSlot::PULLOUT_DIRECTIONS.max
min: ToolSlot::PULLOUT_DIRECTIONS.min,
max: ToolSlot::PULLOUT_DIRECTIONS.max
integer :tool_id, empty: true
string :name
string :openfarm_slug, default: "not-set"
string :plant_stage,
in: CeleryScriptSettingsBag::PLANT_STAGES
time :created_at # TODO: Are we still using this?
time :planted_at, default: 0
string :name
string :openfarm_slug, default: "not-set"
string :plant_stage,
in: CeleryScriptSettingsBag::PLANT_STAGES
time :created_at # TODO: Are we still using this?
time :planted_at, default: 0
boolean :gantry_mounted
end
def validate
@ -68,18 +69,18 @@ module Points
klass_.create!(inputs)
end
private
private
def validate_resource_count
actual = \
actual =
Point.where(device_id: device.id).count
case actual
when POINT_SOFT_LIMIT
device.points.discarded.delete_all
device.tell(GETTING_CLOSE % { actual: actual }, ["fatal_email"])
when POINT_HARD_LIMIT...nil
device.points.discarded.delete_all
add_error(:point_limit, :point_limit, TOO_MANY)
when POINT_SOFT_LIMIT
device.points.discarded.delete_all
device.tell(GETTING_CLOSE % { actual: actual }, ["fatal_email"])
when POINT_HARD_LIMIT...nil
device.points.discarded.delete_all
add_error(:point_limit, :point_limit, TOO_MANY)
end
end

View File

@ -1,3 +1,3 @@
class ToolSlotSerializer < BasePointSerializer
attributes :tool_id, :pullout_direction
attributes :tool_id, :pullout_direction, :gantry_mounted
end

View File

@ -0,0 +1,6 @@
class AddGantryMountedToToolSlots < ActiveRecord::Migration[5.2]
safety_assured
def change
add_column :points, :gantry_mounted, :boolean, default: false
end
end

View File

@ -746,7 +746,8 @@ CREATE TABLE public.points (
tool_id integer,
pullout_direction integer DEFAULT 0,
migrated_at timestamp without time zone,
discarded_at timestamp without time zone
discarded_at timestamp without time zone,
gantry_mounted boolean DEFAULT false
);
@ -2960,6 +2961,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190419052844'),
('20190419174728'),
('20190419174811'),
('20190501143201');
('20190501143201'),
('20190502163453');

View File

@ -322,5 +322,134 @@ describe Api::DevicesController do
expect(settings_default_map_size_x?(device)).to eq(3000)
expect(settings_default_map_size_y?(device)).to eq(1500)
end
it "seeds accounts with Genesis XL 1.4 data" do
start_tests "xl_1.4"
expect(peripherals_lighting?(device).pin).to eq(7)
expect(peripherals_peripheral_4?(device).pin).to eq(10)
expect(peripherals_peripheral_5?(device).pin).to eq(12)
expect(peripherals_vacuum?(device).pin).to be(9)
expect(peripherals_water?(device).pin).to be(8)
expect(pin_bindings_button_1?(device).special_action).to eq("emergency_lock")
expect(pin_bindings_button_2?(device).special_action).to eq("emergency_unlock")
expect(plants?(device)).to be true
expect(sensors_soil_sensor?(device).pin).to eq(59)
expect(sensors_tool_verification?(device).pin).to eq(63)
expect(settings_device_name?(device)).to eq("FarmBot Genesis XL")
expect(settings_enable_encoders?(device)).to be(true)
expect(settings_firmware?(device)).to eq("farmduino")
expect(tool_slots_slot_1?(device).name).to eq("Seeder")
expect(tool_slots_slot_2?(device).name).to eq("Seed Bin")
expect(tool_slots_slot_3?(device).name).to eq("Seed Tray")
expect(tool_slots_slot_4?(device).name).to eq("Watering Nozzle")
expect(tool_slots_slot_5?(device).name).to eq("Soil Sensor")
expect(tool_slots_slot_6?(device).name).to eq("Weeder")
expect(tools_seed_bin?(device)).to be
expect(tools_seed_tray?(device)).to be
expect(tools_seed_trough_1?(device)).to_not be
expect(tools_seed_trough_2?(device)).to_not be
expect(tools_seed_trough_3?(device)).to_not be
expect(tools_seeder?(device)).to be_kind_of(Tool)
expect(tools_soil_sensor?(device)).to be_kind_of(Tool)
expect(tools_watering_nozzle?(device)).to be_kind_of(Tool)
expect(tools_weeder?(device)).to be_kind_of(Tool)
expect(sequences_mount_tool?(device)).to be
expect(sequences_pickup_seed_genesis?(device)).to be
expect(sequences_pickup_seed_express?(device)).to_not be
expect(sequences_plant_seed?(device)).to be_kind_of(Sequence)
expect(sequences_take_photo_of_plant?(device)).to be_kind_of(Sequence)
expect(sequences_tool_error?(device)).to be_kind_of(Sequence)
expect(sequences_unmount_tool?(device)).to be_kind_of(Sequence)
expect(sequences_water_plant?(device)).to be_kind_of(Sequence)
expect(settings_default_map_size_x?(device)).to eq(6000)
expect(settings_default_map_size_y?(device)).to eq(3000)
end
it "seeds accounts with Express 1.0 data" do
start_tests "express_1.0"
expect(peripherals_lighting?(device).pin).to eq(7)
expect(peripherals_peripheral_4?(device).pin).to eq(10)
expect(peripherals_peripheral_5?(device).pin).to eq(12)
expect(peripherals_vacuum?(device).pin).to be(9)
expect(peripherals_water?(device).pin).to be(8)
expect(pin_bindings_button_1?(device).special_action).to eq("emergency_lock")
expect(pin_bindings_button_2?(device).special_action).to eq("emergency_unlock")
expect(plants?(device)).to be true
expect(sensors_soil_sensor?(device)).to_not be
expect(sensors_tool_verification?(device)).to_not be
expect(settings_device_name?(device)).to eq("FarmBot Express")
expect(settings_enable_encoders?(device)).to be(false)
expect(settings_firmware?(device)).to eq("express_v10")
expect(tool_slots_slot_1?(device).name).to eq("Seed Trough 1")
expect(tool_slots_slot_2?(device).name).to eq("Seed Trough 2")
expect(tool_slots_slot_3?(device).name).to eq("Seed Trough 3")
expect(tool_slots_slot_4?(device)).to_not be
expect(tool_slots_slot_5?(device)).to_not be
expect(tool_slots_slot_6?(device)).to_not be
expect(tools_seed_bin?(device)).to_not be
expect(tools_seed_tray?(device)).to_not be
expect(tools_seed_trough_1?(device)).to be
expect(tools_seed_trough_2?(device)).to be
expect(tools_seed_trough_3?(device)).to be
expect(tools_seeder?(device)).to_not be
expect(tools_soil_sensor?(device)).to_not be
expect(tools_watering_nozzle?(device)).to_not be
expect(tools_weeder?(device)).to_not be
expect(sequences_mount_tool?(device)).to_not be
expect(sequences_pickup_seed_genesis?(device)).to_not be
expect(sequences_pickup_seed_express?(device)).to be
expect(sequences_plant_seed?(device)).to be_kind_of(Sequence)
expect(sequences_take_photo_of_plant?(device)).to be_kind_of(Sequence)
expect(sequences_tool_error?(device)).to_not be
expect(sequences_unmount_tool?(device)).to_not be
expect(sequences_water_plant?(device)).to be_kind_of(Sequence)
expect(settings_default_map_size_x?(device)).to eq(3000)
expect(settings_default_map_size_y?(device)).to eq(1200)
end
it "seeds accounts with Express XL 1.0 data" do
start_tests "express_xl_1.0"
expect(peripherals_lighting?(device).pin).to eq(7)
expect(peripherals_peripheral_4?(device).pin).to eq(10)
expect(peripherals_peripheral_5?(device).pin).to eq(12)
expect(peripherals_vacuum?(device).pin).to be(9)
expect(peripherals_water?(device).pin).to be(8)
expect(pin_bindings_button_1?(device).special_action).to eq("emergency_lock")
expect(pin_bindings_button_2?(device).special_action).to eq("emergency_unlock")
expect(plants?(device)).to be true
expect(sensors_soil_sensor?(device)).to_not be
expect(sensors_tool_verification?(device)).to_not be
expect(settings_device_name?(device)).to eq("FarmBot Express XL")
expect(settings_enable_encoders?(device)).to be(false)
expect(settings_firmware?(device)).to eq("express_v10")
expect(tool_slots_slot_1?(device).name).to eq("Seed Trough 1")
expect(tool_slots_slot_2?(device).name).to eq("Seed Trough 2")
expect(tool_slots_slot_3?(device).name).to eq("Seed Trough 3")
expect(tool_slots_slot_4?(device)).to_not be
expect(tool_slots_slot_5?(device)).to_not be
expect(tool_slots_slot_6?(device)).to_not be
expect(tools_seed_bin?(device)).to_not be
expect(tools_seed_tray?(device)).to_not be
expect(tools_seed_trough_1?(device)).to be
expect(tools_seed_trough_2?(device)).to be
expect(tools_seed_trough_3?(device)).to be
expect(tools_seeder?(device)).to_not be
expect(tools_soil_sensor?(device)).to_not be
expect(tools_watering_nozzle?(device)).to_not be
expect(tools_weeder?(device)).to_not be
expect(sequences_mount_tool?(device)).to_not be
expect(sequences_pickup_seed_genesis?(device)).to_not be
expect(sequences_pickup_seed_express?(device)).to be
expect(sequences_plant_seed?(device)).to be_kind_of(Sequence)
expect(sequences_take_photo_of_plant?(device)).to be_kind_of(Sequence)
expect(sequences_tool_error?(device)).to_not be
expect(sequences_unmount_tool?(device)).to_not be
expect(sequences_water_plant?(device)).to be_kind_of(Sequence)
expect(settings_default_map_size_x?(device)).to eq(6000)
expect(settings_default_map_size_y?(device)).to eq(2400)
end
end
end

View File

@ -1,4 +1,4 @@
require 'spec_helper'
require "spec_helper"
describe Points::Create do
let(:device) { FactoryBot.create(:device) }
@ -21,21 +21,32 @@ describe Points::Create do
it "warns users when they hit the soft resource limit" do
with_fake_limits do
allow(device)
.to receive(:tell).with(Points::Create::GETTING_CLOSE, ["fatal_email"])
allow(device).to receive(:tell).with(Points::Create::GETTING_CLOSE, ["fatal_email"])
Points::Create::POINT_SOFT_LIMIT.times do
expect(Points::Create.run(params).errors).to be nil
end
end
end
it "creates a gantry_mounted tool slot" do
p = { x: 0,
y: 10,
z: -100,
device: FactoryBot.create(:device),
gantry_mounted: true,
pointer_type: "ToolSlot" }
slot = Points::Create.run!(p)
p.map { |(k, v)| expect(slot.send(k)).to eq(v) }
end
it "stops users when they hit the hard limit" do
with_fake_limits do
params = { x: 0,
y: 0,
z: 0,
device: device,
pointer_type: "GenericPointer", }
params = { x: 0,
y: 0,
z: 0,
device: device,
pointer_type: "GenericPointer" }
Points::Create::POINT_HARD_LIMIT.times do
expect(Points::Create.run(params).errors).to be nil