From 321eaf1a86b53e3473ffa5329cbbd5dd226e6b71 Mon Sep 17 00:00:00 2001 From: TimEvWw Date: Thu, 17 Apr 2014 13:26:12 -0100 Subject: [PATCH] sending schedule to controller --- schedule/config/mongo.yml | 76 ++++++++++ schedule/credentials.yml | 4 + schedule/lib/botcomm.rb | 71 +++++++++ schedule/lib/cropschedule.rb | 118 +++++++++++++++ schedule/lib/database/dbcommand.rb | 157 ++++++++++++++++++++ schedule/lib/database/dbfarmbot.rb | 134 +++++++++++++++++ schedule/lib/skynet.rb | 15 ++ schedule/lib/skynet/credentials.rb | 49 +++++++ schedule/lib/skynet/messagehandler.rb | 201 ++++++++++++++++++++++++++ schedule/lib/skynet/skynet.rb | 59 ++++++++ schedule/lib/skynet/web_socket.rb | 33 +++++ schedule/sendschedule.rb | 44 ++++++ schedule/testmenu.rb | 104 +++++++++++++ send_schedule | 1 - 14 files changed, 1065 insertions(+), 1 deletion(-) create mode 100644 schedule/config/mongo.yml create mode 100644 schedule/credentials.yml create mode 100644 schedule/lib/botcomm.rb create mode 100644 schedule/lib/cropschedule.rb create mode 100644 schedule/lib/database/dbcommand.rb create mode 100644 schedule/lib/database/dbfarmbot.rb create mode 100644 schedule/lib/skynet.rb create mode 100644 schedule/lib/skynet/credentials.rb create mode 100644 schedule/lib/skynet/messagehandler.rb create mode 100644 schedule/lib/skynet/skynet.rb create mode 100644 schedule/lib/skynet/web_socket.rb create mode 100644 schedule/sendschedule.rb create mode 100644 schedule/testmenu.rb delete mode 160000 send_schedule diff --git a/schedule/config/mongo.yml b/schedule/config/mongo.yml new file mode 100644 index 000000000..f8169dd9c --- /dev/null +++ b/schedule/config/mongo.yml @@ -0,0 +1,76 @@ +development: + # Configure available database sessions. (required) + sessions: + # Defines the default session. (required) + default: + # Defines the name of the default database that Mongoid can connect to. + # (required). + database: farmbot_backend_development + # Provides the hosts the default session can connect to. Must be an array + # of host:port pairs. (required) + hosts: + - localhost:27017 + options: + # Change the default write concern. (default = { w: 1 }) + # write: + # w: 1 + + # Change the default consistency model to primary, secondary. + # 'secondary' will send reads to secondaries, 'primary' sends everything + # to master. (default: primary) + # read: secondary_preferred + + # How many times Moped should attempt to retry an operation after + # failure. (default: 30) + # max_retries: 30 + + # The time in seconds that Moped should wait before retrying an + # operation on failure. (default: 1) + # retry_interval: 1 + # Configure Mongoid specific options. (optional) + options: + # Enable the identity map, needed for eager loading. (default: false) + # identity_map_enabled: false + + # Includes the root model name in json serialization. (default: false) + # include_root_in_json: false + + # Include the _type field in serializaion. (default: false) + # include_type_for_serialization: false + + # Preload all models in development, needed when models use + # inheritance. (default: false) + # preload_models: false + + # Protect id and type from mass assignment. (default: true) + # protect_sensitive_fields: true + + # Raise an error when performing a #find and the document is not found. + # (default: true) + # raise_not_found_error: true + + # Raise an error when defining a scope with the same name as an + # existing method. (default: false) + # scope_overwrite_exception: false + + # Skip the database version check, used when connecting to a db without + # admin access. (default: false) + # skip_version_check: false + + # Use Active Support's time zone in conversions. (default: true) + # use_activesupport_time_zone: true + + # Ensure all times are UTC in the app side. (default: false) + # use_utc: false +test: + sessions: + default: + database: farmbot_backend_test + hosts: + - localhost:27017 + options: + read: primary + # In the test environment we lower the retries and retry interval to + # low amounts for fast failures. + max_retries: 1 + retry_interval: 0 diff --git a/schedule/credentials.yml b/schedule/credentials.yml new file mode 100644 index 000000000..07d096b43 --- /dev/null +++ b/schedule/credentials.yml @@ -0,0 +1,4 @@ +--- +:uuid: 40b8cfdf-92e9-450d-b603-1e9efbbecf47 +:token: !binary |- + MzIwMTc3M2IwZDA3N2NmM2ZlZmQ5ZDQwZjNiZGE1NmI= diff --git a/schedule/lib/botcomm.rb b/schedule/lib/botcomm.rb new file mode 100644 index 000000000..7752cd27c --- /dev/null +++ b/schedule/lib/botcomm.rb @@ -0,0 +1,71 @@ + +# #################################### +# Send something to farmbot controller +# #################################### + +class FarmBotControllerComm + + # send command to farmbot + def send_single_command(action, x, y, z, amount, speed, delay) + + $skynet.confirmed = false + command = + { + :message_type => 'single_command', + :time_stamp => Time.now.to_f.to_s, + :command => { + :action => action, + :x => x, + :y => y, + :z => z, + :speed => speed, + :amount => amount, + :delay => delay + }} + + + $skynet.send_message($farmbot_uuid, command) + return wait_for_confirmation() + + end + + + # send schedule to farmbot + def send_schedule(uuid, schedule) + + $skynet.confirmed = false + + sched_hash = schedule.to_hash + sched_hash[:message_type] = 'crop_schedule_update' + sched_hash[:time_stamp] = Time.now.to_f.to_s + + puts sched_hash + + $skynet.send_message(uuid, sched_hash) + return wait_for_confirmation() + + end + + def wait_for_confirmation + puts 'waiting for confirmation' + count = 0 + while $skynet.confirmed != true and count < 10 + sleep 0.5 + print '.' + count += 1 + end + + puts '' + + if $skynet.confirmed + puts 'confirmation received' + return true + else + puts 'confirmation timed out' + sleep 2 + return false + end + + end + +end \ No newline at end of file diff --git a/schedule/lib/cropschedule.rb b/schedule/lib/cropschedule.rb new file mode 100644 index 000000000..d608d8483 --- /dev/null +++ b/schedule/lib/cropschedule.rb @@ -0,0 +1,118 @@ + +# +# Classes to make a schedule that can be transmitted to the bot +# + +class CropSchedule + + attr_accessor :crop_id + + def initialize + @commands = Array.new + end + + def read_from_db(crop) + @crop_id = crop.crop_id + + crop.scheduled_commands.each do |dbcommand| + + command = CropScheduleCommand.new + command.read_from_db(dbcommand) + add_command(command) + + end + end + + def to_hash + command_nr = 0 + schedule_hash = {:crop_id => @crop_id, :commands => {} } + commands = Hash.new + @commands.each do |command| + command_nr += 1 + commands["command_#{command_nr}"]= command.to_hash + end + schedule_hash[:commands] = commands + return schedule_hash + end + + def add_command(command) + + @commands << command + + end + +end + +class CropScheduleCommand + + attr_accessor :scheduled_time + + def initialize + @command_lines = Array.new + end + + def read_from_db(command) +puts command +puts command.scheduled_time + @scheduled_time = command.scheduled_time + seq = 0 + + command.scheduled_command_lines.each do |dbline| + + seq += 1 + line = CropScheduleCommandLine.new + line.read_from_db(dbline, seq) + add_command_line(line) + + end + end + + def to_hash + sequence_nr = 0 + command_hash = {:scheduled_time => @scheduled_time, :command_lines => {} } + command_lines = Hash.new + @command_lines.each do |line| + sequence_nr += 1 + line.sequence_nr = sequence_nr + command_lines["command_line_#{sequence_nr}"]= line.to_hash + end + command_hash[:command_lines] = command_lines + return command_hash + end + + def add_command_line(line) + @command_lines << line + end + +end + +class CropScheduleCommandLine + + attr_accessor :action, :x, :y, :z, :amount, :speed, :sequence_nr + + def read_from_db(line, sequence_nr) + @action = line.action + @x = line.coord_x + @y = line.coord_y + @z = line.coord_z + @amount = line.amount + @speed = line.speed + @sequence_nr = sequence_nr + end + + def to_hash + + line = { + :action => @action , + :x => @x , + :y => @y , + :z => @z , + :amount => @amount , + :speed => @speed , + :sequence_nr => @sequence_nr + } + return line + + end + +end diff --git a/schedule/lib/database/dbcommand.rb b/schedule/lib/database/dbcommand.rb new file mode 100644 index 000000000..ddbc40dc0 --- /dev/null +++ b/schedule/lib/database/dbcommand.rb @@ -0,0 +1,157 @@ +require 'bson' +require 'mongo' +require 'mongoid' + +# Data classes +# This class is dedicated to retrieving and inserting commands into the schedule +# queue for the farm bot Mongo is used as the database, Mongoid as the +# databasemapper + +class Command + include Mongoid::Document + + embeds_many :commandlines + + field :plant_id + field :crop_id + field :scheduled_time + field :executed_time + field :status + +end + +class Commandline + include Mongoid::Document + + embedded_in :command + #belongs_to :command + + field :action + field :coord_x + field :coord_y + field :coord_z + field :speed + field :amount +end + +class Refresh + include Mongoid::Document + + field :name + field :value +end + +# Access class for the database + +class DbAccess + + def initialize + Mongoid.load!("config/mongo.yml", :development) + @last_command_retrieved = nil + @refresh_value = 0 + @refresh_value_new = 0 + + @new_command = nil + end + + def test + db_connection = Mongo::Connection.new + db_farmbot = db_connection['farmbot_development'] + db_schedule = db_farmbot['schedule'] + + db_connection.database_names.each do |name| + db = db_connection.db(name) + db.collections.each do |collection| + puts "#{name} - #{collection.name}" + end + end + end + + def create_new_command(scheduled_time, crop_id) + @new_command = Command.new + @new_command.scheduled_time = scheduled_time + @new_command.crop_id = crop_id + end + + def add_command_line(action, x = 0, y = 0, z = 0, speed = 0, amount = 0) + if @new_command != nil + line = Commandline.new + line.action = action + line.coord_x = x + line.coord_y = y + line.coord_z = z + line.speed = speed + line.amount = amount + if @new_command.commandlines == nil + @new_command.commandlines = [ line ] + else + @new_command.commandlines << line + end + end + end + + def save_new_command + if @new_command != nil + @new_command.status = 'scheduled' + @new_command.save + end + increment_refresh + end + + def clear_schedule + Command.where( + :status => 'scheduled', + :scheduled_time.ne => nil + ).order_by([:scheduled_time,:asc]).each do |command| + + command.status = 'deleted' + command.save + + end + end + + def clear_crop_schedule(crop_id) + Command.where( + :status => 'scheduled', + :scheduled_time.ne => nil, + :crop_id => crop_id + ).order_by([:scheduled_time,:asc]).each do |command| + + command.status = 'deleted' + command.save + + end + end + + def get_command_to_execute + @last_command_retrieved = Command.where( + :status => 'scheduled', + :scheduled_time.ne => nil + ).order_by([:scheduled_time,:asc]).first + @last_command_retrieved + end + + def set_command_to_execute_status(new_status) + if @last_command_retrieved != nil + @last_command_retrieved.status = new_status + @last_command_retrieved.save + end + end + + def check_refresh + r = Refresh.where(:name => 'FarmBotControllerSchedule').first_or_initialize + @refresh_value_new = r.value.to_i + return @refresh_value_new != @refresh_value + end + + def save_refresh + @refresh_value = @refresh_value_new + end + + def increment_refresh + r = Refresh.where(:name => 'FarmBotControllerSchedule').first_or_initialize + r.value = r.value.to_i + 1 + r.save + end + +end \ No newline at end of file diff --git a/schedule/lib/database/dbfarmbot.rb b/schedule/lib/database/dbfarmbot.rb new file mode 100644 index 000000000..246e05bbe --- /dev/null +++ b/schedule/lib/database/dbfarmbot.rb @@ -0,0 +1,134 @@ +# This module holds our data definitions to store all basic plant and watering data +# Mongo is used as the database, Mongoid as the databasemapper + +require 'bson' +require 'mongo' +require 'mongoid' + +#require 'bson_ext' + +# The different farmbots are stored here + +class FarmBot + include Mongoid::Document + + embeds_many :crops + + field :active + field :name + field :environmental_coefficient + field :uuid + + # also needs user settings, security and whatsnot + +end + +# The list of crops tended by one farm bot. The crop is planted as a seed (age = 0) or when it has already sprouted. +# Coordinates x, y and z are used to drive the robot to the right place +# The age of maturing and harvesting should be customized to local conditions + +class Crop + include Mongoid::Document + + embedded_in :farmbot + embeds_many :grow_coefficients + embeds_many :waterings + embeds_many :historic_actions + embeds_many :scheduled_commands + + field :plant_type + field :coord_x + field :coord_y + field :coord_z + field :radius + field :height + field :status + + field :date_at_planting + field :age_at_planting + field :age_at_fully_grown + field :age_at_harvest + + field :valid_data + field :crop_id + +end + +# Coefficients are used by the evapotransporation system. It expresses the amount of water (mm/day) the plant needs for a good growth at a certain age +# The values for the coefficient is the result of the local climate reference value multiplied with the +# The age is represented as a precentage, where 100% is fully grown and 200% is ready for harvesting + +# a typical curve for a crops. the Y axis is here a multiplication factor for the reference crops (fictional grass or alfalfa) +# +# 1.0 ***** +# *| ** +# * | *** +# * | | +# ** | | +# 0.1 *** | | +# | | | +# 0% 100% 200% + +class GrowCoefficient + include Mongoid::Document + + embedded_in :crop + + field :age_in_percentage + field :amount_water_manual + +end + +# These are the times when the robot is supposed to water the crop + +class Watering + include Mongoid::Document + + embedded_in :crop + + field :time + field :percentage +end + +# A log of what happended to the plant. Waterings and rainfall are the most important probably + +class HistoricAction + include Mongoid::Document + + embedded_in :crop + + field :start_time + field :stop_time + field :action + field :amount +end + +# This is the schedule for the next hours/days that the bot has to execute. This is synchronized to the bot. + +class ScheduledCommand + include Mongoid::Document + + embedded_in :crop + embeds_many :scheduled_command_lines + + + field :crop_id + field :schedule_id + field :one_time_command + field :scheduled_time + field :command_id +end + +class ScheduledCommandLine + include Mongoid::Document + + embedded_in :scheduled_command + + field :action + field :coord_x + field :coord_y + field :coord_z + field :speed + field :amount +end + diff --git a/schedule/lib/skynet.rb b/schedule/lib/skynet.rb new file mode 100644 index 000000000..dba52ad81 --- /dev/null +++ b/schedule/lib/skynet.rb @@ -0,0 +1,15 @@ + + +require_relative 'skynet/skynet' + +# The unfortunate use of globals in this project: The SocketIO library we use to +# talk to skynet stores blocks as lambdas and calls them later under a different +# context than that which they were defined. This means that even though we +# define the .on() events within the `Device` class, self does NOT refer to the +# device, but rather the current socket connection. Using a global is a quick +# fix to ensure we always have easy access to the device. Pull requests welcome. + +$skynet = Skynet.new + +#TODO: Daemonize this script: +#https://www.ruby-toolbox.com/categories/daemonizing \ No newline at end of file diff --git a/schedule/lib/skynet/credentials.rb b/schedule/lib/skynet/credentials.rb new file mode 100644 index 000000000..2825d5538 --- /dev/null +++ b/schedule/lib/skynet/credentials.rb @@ -0,0 +1,49 @@ +require 'securerandom' + +module Credentials + # Stores a references to the credentials yml file, which is used to persist + # the user's skynet Token / ID across sessions. Returns String. parameterless + def credentials_file + 'credentials.yml' + end + + # Returns Hash containing the a :uuid and :token key. Triggers the creation of + # new credentials if the current ones are found to be invalid. + def credentials + if valid_credentials? + return load_credentials + else + return create_credentials + end + end + + # Validates that the credentials file has a :uuid and :token key. Returns Bool + # + def valid_credentials? + if File.file?(credentials_file) + cred = load_credentials + return true if cred.has_key?(:uuid) && cred.has_key?(:token) + end + return false + end + + # Uses the ruby securerandom library to make a new :uuid and :token. Also + # registers with a new device :uuid and :token on skynet.im . Returns Hash + # containing :uuid and :token key. + def create_credentials + hash = { + uuid: (@uuid = SecureRandom.uuid), + token: (@token = SecureRandom.hex) + } + `curl -s -X POST -d 'uuid=#{@uuid}&token=#{@token}&type=farmbot' \ + http://skynet.im/devices` + File.open(credentials_file, 'w+') {|file| file.write(hash.to_yaml) } + return hash + end + + ### Loads the credentials file from disk and returns it as a ruby hash. + def load_credentials + return YAML.load(File.read(credentials_file)) + end + +end \ No newline at end of file diff --git a/schedule/lib/skynet/messagehandler.rb b/schedule/lib/skynet/messagehandler.rb new file mode 100644 index 000000000..a92e3326a --- /dev/null +++ b/schedule/lib/skynet/messagehandler.rb @@ -0,0 +1,201 @@ +require 'json' +#require './lib/database/commandqueue.rb' +require './lib/database/dbcommand.rb' +require 'time' + +# Get the JSON command, received through skynet, and send it to the farmbot +# command queue Parses JSON messages received through SkyNet. +class MessageHandler + + attr_accessor :message + + def initialize + @dbaccess = DbAccess.new + @last_time_stamp = '' + end + + # A list of MessageHandler methods (as strings) that a Skynet User may access. + # + def whitelist + ["single_command","crop_schedule_update"] + end + + # Main entry point for (Hash) commands coming in over SkyNet. + # { + # "message_type" : "single_command", + # "time_stamp" : 2001-01-01 01:01:01.001 + # "command" : { + # "action" : "HOME X", + # "x" : 1, + # "y" : 2, + # "z" : 3, + # "speed" : "FAST", + # "amount" : 5, + # "delay" : 6 + # } + # } + + def handle_message(message) + + puts 'handle_message' + #puts message + #puts message['message'] + + @message = message['message'] + #fromUuid = message['fromUuid'] + #puts fromUuid + + requested_command = message['message']["message_type"].to_s.downcase + #puts requested_command + + if whitelist.include?(requested_command) + #puts 'sending' + self.send(requested_command, message) + else + self.error(message) + end + end + + # Handles an erorr (typically, an unauthorized or unknown message). Returns + # Hash. + def error + return {error: ""} + end + + def single_command(message) + + puts 'single_command' + #puts message + + time_stamp = message['message']['time_stamp'] + sender = message['fromUuid'] + + if time_stamp != @last_time_stamp + @last_time_stamp = time_stamp + + + # send the command to the queue + delay = message['message']['command']['delay'] + action = message['message']['command']['action'] + x = message['message']['command']['x'] + y = message['message']['command']['y'] + z = message['message']['command']['z'] + speed = message['message']['command']['speed'] + amount = message['message']['command']['amount'] + delay = message['message']['command']['delay'] + + puts "[new command] received at #{Time.now} from #{sender}" + puts "[#{action}] x: #{x}, y: #{y}, z: #{z}, speed: #{speed}, amount: #{amount} delay: #{delay}" + + @dbaccess.create_new_command(Time.now + delay.to_i,'single_command') + @dbaccess.add_command_line(action, x.to_i, y.to_i, z.to_i, speed.to_s, amount.to_i) + @dbaccess.save_new_command + + $skynet.confirmed = false + + command = + { + :message_type => 'confirmation', + :time_stamp => Time.now.to_f.to_s, + :confirm_id => time_stamp + } + + $skynet.send_message(sender, command) + + end + end + + def crop_schedule_update(message) + + puts 'crop_schedule_update' + #puts message + + time_stamp = message['message']['time_stamp'] + sender = message['fromUuid'] + + puts "time_stamp #{time_stamp}" + puts "sender #{sender}" + + if time_stamp != @last_time_stamp + @last_time_stamp = time_stamp + + + message_contents = message['message'] + #puts message_contents + + crop_id = message_contents['crop_id'] + puts crop_id + + puts 'removing old crop schedule' + @dbaccess.clear_crop_schedule(crop_id) + + message_contents['commands'].each do |command| + + #puts command + #puts command.class + #puts command[0] + #puts command[0].class + #puts command[1] + #puts command[1].class + + scheduled_time = Time.parse(command[1]['scheduled_time']) + + @dbaccess.create_new_command(scheduled_time, crop_id) + #@dbaccess.create_new_command(Time.now, 'debug') + puts scheduled_time + puts Time.now + + command[1]['command_lines'].each do |command_line| + + action = command_line[1]['action'] + x = command_line[1]['x'] + y = command_line[1]['y'] + z = command_line[1]['z'] + speed = command_line[1]['speed'] + amount = command_line[1]['amount'] + + + puts "[#{action}] x: #{x}, y: #{y}, z: #{z}, speed: #{speed}, amount: #{amount}" + @dbaccess.add_command_line(action, x.to_i, y.to_i, z.to_i, speed.to_s, amount.to_i) + + end + + @dbaccess.save_new_command + + end + + # send the command to the queue + #delay = message['message']['command']['delay'] + #action = message['message']['command']['action'] + #x = message['message']['command']['x'] + #y = message['message']['command']['y'] + #z = message['message']['command']['z'] + #speed = message['message']['command']['speed'] + #amount = message['message']['command']['amount'] + #delay = message['message']['command']['delay'] + + #puts "[new command] received at #{Time.now} from #{sender}" + #puts "[#{action}] x: #{x}, y: #{y}, z: #{z}, speed: #{speed}, amount: #{amount} delay: #{delay}" + + #@dbaccess.create_new_command(Time.now + delay.to_i) + #@dbaccess.add_command_line(action, x.to_i, y.to_i, z.to_i, speed.to_s, amount.to_i) + #@dbaccess.save_new_command + + puts 'sending comfirmation' + + $skynet.confirmed = false + + command = + { + :message_type => 'confirmation', + :time_stamp => Time.now.to_f.to_s, + :confirm_id => time_stamp + } + + $skynet.send_message(sender, command) + + end + end + + +end diff --git a/schedule/lib/skynet/skynet.rb b/schedule/lib/skynet/skynet.rb new file mode 100644 index 000000000..1e4459b91 --- /dev/null +++ b/schedule/lib/skynet/skynet.rb @@ -0,0 +1,59 @@ +require 'json' + +require_relative 'credentials' +require_relative 'web_socket' +require_relative 'messagehandler.rb' + +# The Device class is temporarily inheriting from Tim's HardwareInterface. +# Eventually, we should merge the two projects, but this is good enough for now. +class Skynet + + include Credentials, WebSocket + + attr_accessor :socket, :uuid, :token, :identified, :confirmed, + :confirmation_id + + # On instantiation #new sets the @uuid, @token variables, connects to skynet + def initialize + super + identified = false + creds = credentials + @uuid = creds[:uuid] + @token = creds[:token] + @socket = SocketIO::Client::Simple.connect 'http://skynet.im:80' + @confirmed = false + + create_socket_events + + puts "uuid: #{@uuid}" + + @message_handler = MessageHandler.new + end + + def send_message(devices, message_hash ) + @socket.emit("message",{:devices => devices, :message => message_hash}) + end + + # Acts as the entry point for message traffic captured from Skynet.im. + # This method is a stub for now until I have time to merge into Tim's + # controller code. Returns a MessageHandler object (a class yet created). + #def handle_message(channel, message) + def handle_message(message) + +puts "> message received at #{Time.now}" +#puts message + + if message.class.to_s == 'Hash' + @message_handler.handle_message(message) + end + + if message.class.to_s == 'String' + message_hash = JSON.parse(message) + @message_handler.handle_message(message_hash) + end + + rescue + raise "Runtime error while attempting to parse message: #{message}." + end + +end diff --git a/schedule/lib/skynet/web_socket.rb b/schedule/lib/skynet/web_socket.rb new file mode 100644 index 000000000..b4c2f42c8 --- /dev/null +++ b/schedule/lib/skynet/web_socket.rb @@ -0,0 +1,33 @@ +require 'socket.io-client-simple' + +module WebSocket + ### Bootstraps all the events for skynet in the correct order. Returns Int. + def create_socket_events + #OTHER EVENTS: :identify, :identity, :ready, :disconnect, :message + create_identify_event + create_message_event + end + + #Handles self identification on skynet by responding to the :indentify with a + #:identity event / credentials Hash. + def create_identify_event + @socket.on :identify do |data| + self.emit :identity, { + uuid: $skynet.uuid, + token: $skynet.token, + socketid: data['socketid']} + $skynet.identified = true + end + end + + ### Routes all skynet messages to handle_event() for interpretation. + def create_message_event + #@socket.on :message do |channel, message| + # $skynet.handle_message(channel, message) + #end + @socket.on :message do |message| + $skynet.handle_message(message) + end + end + +end \ No newline at end of file diff --git a/schedule/sendschedule.rb b/schedule/sendschedule.rb new file mode 100644 index 000000000..c3e865b88 --- /dev/null +++ b/schedule/sendschedule.rb @@ -0,0 +1,44 @@ + +$farmbot_uuid = "063df52b-0698-4e1c-b2bb-4c0890019782" + +require_relative 'lib/skynet/skynet' +require_relative 'lib/botcomm' +require_relative 'lib/cropschedule' +require_relative 'lib/database/dbcommand' +require_relative 'lib/database/dbfarmbot' + +puts '[FarmBot schedule transmit]' +puts 'starting up' + +# connecting to skynet framework +$skynet = Skynet.new + +$farmbot_comm = FarmBotControllerComm.new + +while $skynet.identified != true + sleep 0.5 + print '.' +end +puts '' + +puts 'connecting to database' + +Mongoid.load!("config/mongo.yml", :development) + +puts 'checking list of bots' + + FarmBot.where(:active => true).order_by([:name,:asc]).each do |farmbot| + puts "checking bot #{farmbot.name} uuid #(farmbot.uuid)" + + farmbot.crops.where(:valid_data => true).each do |crop| + + puts "crop type=#{crop.plant_type} @ x=#{crop.coord_x} y=#{crop.coord_y}" + + crop_schedule = CropSchedule.new + crop_schedule.read_from_db( crop ) + + $farmbot_comm.send_schedule(farmbot.uuid,crop_schedule) + + end + +end \ No newline at end of file diff --git a/schedule/testmenu.rb b/schedule/testmenu.rb new file mode 100644 index 000000000..9c8e27b1f --- /dev/null +++ b/schedule/testmenu.rb @@ -0,0 +1,104 @@ + +$farmbot_uuid = "063df52b-0698-4e1c-b2bb-4c0890019782" + +require_relative 'lib/device/device' +require_relative 'lib/botcomm' + +puts '[FarmBot Remote Control]' +puts 'starting up' + +# connecting to skynet framework +$device = Device.new + +$farmbot_comm = FarmBotControllerComm.new + +while $device.identified != true + sleep 0.5 + print '.' +end +puts '' + +# send schedule to farmbot +def send_singe_command(action, x, y, z, amount, speed, delay) + + $farmbot_comm.send_single_command(action, x, y, z, amount, speed, delay) + +end + + +$shutdown = 0 + +# just a little menu for testing + +$move_size = 10 +$command_delay = 0 + +while $shutdown == 0 do + + system('cls') + system('clear') + + puts '[FarmBot Controller Menu]' + puts '' + puts 'p - stop' + puts '' + puts "move size = #{$move_size}" + puts "command delay = #{$command_delay}" + puts '' + puts 'w - forward' + puts 's - back' + puts 'a - left' + puts 'd - right' + puts 'r - up' + puts 'f - down' + puts '' + puts 'z - home z axis' + puts 'x - home x axis' + puts 'c - home y axis' + puts '' + puts 'y - dose water' + puts '' + puts 'q - step size' + puts 'g - delay seconds' + puts '' + print 'command > ' + input = gets + puts '' + + case input.upcase[0] + when "P" # Quit + $shutdown = 1 + puts 'Shutting down...' + when "O" # Get status + puts 'Not implemented yet. Press \'Enter\' key to continue.' + gets + when "Q" # Set step size + print 'Enter new step size > ' + move_size_temp = gets + $move_size = move_size_temp.to_i if move_size_temp.to_i > 0 + when "G" # Set step delay (seconds) + print 'Enter new delay in seconds > ' + command_delay_temp = gets + $command_delay = command_delay_temp.to_i if command_delay_temp.to_i > 0 + when "Y" # Water + send_single_command('DOSE WATER', 0, 0, 0, 15, 0, $command_delay) + when "Z" # Move to home + send_single_command('HOME Z', 0, 0, 0, 0, 0, $command_delay) + when "X" # Move to home + send_single_command('HOME X', 0, 0, 0, 0, 0, $command_delay) + when "C" # Move to home + send_single_command('HOME Y',0 ,0 ,-$move_size, 0, 0, $command_delay) + when "W" # Move forward + send_single_command('MOVE RELATIVE',0,$move_size, 0, 0, 0, $command_delay) + when "S" # Move back + send_single_command('MOVE RELATIVE',0,-$move_size, 0, 0, 0, $command_delay) + when "A" # Move left + send_single_command('MOVE RELATIVE', -$move_size, 0, 0, 0, 0, $command_delay) + when "D" # Move right + send_single_command('MOVE RELATIVE', $move_size, 0, 0, 0, 0, $command_delay) + when "R" # Move up + send_single_command('MOVE RELATIVE', 0, 0, $move_size, 0, 0, $command_delay) + when "F" # Move down + send_single_command("MOVE RELATIVE", 0, 0, -$move_size, 0, 0, $command_delay) + end +end diff --git a/send_schedule b/send_schedule deleted file mode 160000 index 68e4f0cc6..000000000 --- a/send_schedule +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 68e4f0cc61ce622cda65c79c2a3f13557077fb02