Compare commits

...

12 Commits

@ -16,34 +16,6 @@ import shepherd.plugin
#Start new thread, and push ID and core config to api.shepherd.distreon.net/client/update
class UpdateManager():
def __init__(self):
pass
class SequenceUpdate():
Item = namedtuple('Item', ['sequence_number', 'content'])
def __init__(self):
self.items = []
self._sequence_count = 0
self._dirty = False
def _next_sequence_number(self):
# TODO: need to establish a max sequence number, so that it can be compared to half
# that range and wrap around.
self._sequence_count +=1
return self._sequence_count
def mark_as_dirty(self):
self._dirty = True
def add_item(self, item):
self.items.append(self.Item(self._next_sequence_number(), item))
self.mark_as_dirty()
def get_payload():
pass
def process_ack():
pass
client_id = None
control_url = None

@ -171,7 +171,6 @@ def compile_config(default_config_path):
@click.group(invoke_without_command=True)
#help="Path to default config TOML file"
@click.argument('default_config', default="shepherd-default.toml", type=click.Path())
@click.pass_context
def cli(ctx, default_config):
@ -191,8 +190,8 @@ def cli(ctx, default_config):
core_conf, plugin_classes, plugin_configs = compile_config(default_config)
if args.test is None:
control.init_control(core_conf, plugin_configs)
# if args.test is None:
# control.init_control(core_conf, plugin_configs)
scheduler.init_scheduler(core_conf)
plugin.init_plugins(plugin_classes, plugin_configs, core_conf)
@ -209,11 +208,11 @@ def cli(ctx, default_config):
except (KeyboardInterrupt, SystemExit):
pass
@click.argument('plugin_function')
@cli.command()
def test():
if args.test is not None:
(test_plugin, test_func) = args.test.split(':')
func = getattr(shepherd.plugin.plugin_functions[test_plugin], test_func)
def test(plugin_function):
(test_plugin, test_func) = plugin_function.split(':')
func = getattr(plugin.plugin_functions[test_plugin], test_func)
print(func())
return

@ -1,77 +1,48 @@
#!/usr/bin/env python3
import shepherd.config
import shepherd.module
import shepherd.config as shconf
import shepherd.plugin
import sys
import os
import time
import argparse
from gpiozero import OutputDevice, Device
from gpiozero.pins.pigpio import PiGPIOFactory
from shepherd.modules.betterservo import BetterServo
class AphidtrapModule(shepherd.plugin.Plugin):
@staticmethod
def define_config(confdef):
pass
Device.pin_factory = PiGPIOFactory()
def __init__(self, pluginInterface, config):
super().__init__(pluginInterface, config)
APHIDTRAP_LED_PIN = 5 #Out2
class AphidtrapConfDef(shepherd.config.ConfDefinition):
def __init__(self):
super().__init__()
class AphidtrapModule(shepherd.module.SimpleModule):
conf_def = AphidtrapConfDef()
def setup(self):
self.config = config
self.interface = pluginInterface
self.plugins = pluginInterface.other_plugins
self.hooks = pluginInterface.hooks
print("Aphidtrap config:")
print(self.config)
self.led_power = OutputDevice(APHIDTRAP_LED_PIN,
active_high=True,
initial_value=False)
if "picam" in self.plugins:
self.interface.attach_hook("picam", "pre_cam", self.led_on)
self.interface.attach_hook("picam", "post_cam", self.led_off)
elif "usbcam" in self.plugins:
self.interface.attach_hook("usbcam", "pre_cam", self.led_on)
self.interface.attach_hook("usbcam", "post_cam", self.led_off)
else:
raise ValueError("Need to either have picam or usbcam plugin loaded")
def setup_other_modules(self):
self.modules.picam.hook_pre_cam.attach(self.led_on)
self.modules.picam.hook_post_cam.attach(self.led_off)
self.interface.register_function(self.test)
def led_on(self):
self.led_power.on()
self.plugins["scout"].set_out2(True)
def led_off(self):
self.led_power.off()
self.plugins["scout"].set_out2(False)
def main(argv):
argparser = argparse.ArgumentParser(
description='Module for aphidtrap control functions. Run for testing')
argparser.add_argument("configfile", nargs='?', metavar="configfile",
help="Path to configfile", default="conf.toml")
args = argparser.parse_args()
confman = shepherd.config.ConfigManager()
srcdict = {"aphidtrap": {}}
if os.path.isfile(args.configfile):
confman.load(args.configfile)
else:
confman.load(srcdict)
aphidtrap_mod = AphidtrapModule(confman.get_config("aphidtrap", AphidtrapConfDef()),
shepherd.module.Interface(None))
aphidtrap_mod.led_on()
def test(self):
self.led_on()
time.sleep(2)
aphidtrap_mod.led_off()
if __name__ == "__main__":
main(sys.argv[1:])
self.led_off()

@ -25,7 +25,7 @@ class FlytrapPlugin(shepherd.plugin.Plugin):
self.hooks = pluginInterface.hooks
self.root_dir = os.path.expanduser(pluginInterface.coreconfig["root_dir"])
self.id = pluginInterface.coreconfig["id"]
self.id = pluginInterface.coreconfig["name"]
print("Flytrap config:")
print(self.config)

@ -9,7 +9,6 @@ import time
import argparse
class MothtrapPlugin(shepherd.plugin.Plugin):
@staticmethod
def define_config(confdef):
@ -25,26 +24,29 @@ class MothtrapPlugin(shepherd.plugin.Plugin):
self.hooks = pluginInterface.hooks
self.root_dir = os.path.expanduser(pluginInterface.coreconfig["root_dir"])
self.id = pluginInterface.coreconfig["id"]
self.id = pluginInterface.coreconfig["name"]
print("Mothtrap config:")
print(self.config)
#servo_max = self.config["servo_open_pulse"] / 1000000
#servo_min = self.config["servo_closed_pulse"] / 1000000
# if servo_min > servo_max:
# servo_min, servo_max = servo_max, servo_min
#print(F"Supplied min: {servo_min}, max: {servo_max}")
if "picam" in self.plugins:
self.interface.attach_hook("picam", "pre_cam", self.led_on)
self.interface.attach_hook("picam", "post_cam", self.led_off)
self.interface.attach_hook("picam", "post_cam", self.run_servo)
elif "usbcam" in self.plugins:
self.interface.attach_hook("usbcam", "pre_cam", self.led_on)
self.interface.attach_hook("usbcam", "post_cam", self.led_off)
self.interface.attach_hook("usbcam", "post_cam", self.run_servo)
else:
raise ValueError("Need to either have picam or usbcam plugin loaded")
self.interface.register_function(self.test)

@ -43,7 +43,7 @@ class PiCamPlugin(shepherd.plugin.Plugin):
confdef.add_def('jpeg_quality', shconf.IntDef(default=80, minval=60, maxval=95, optional=True,
helptext="JPEG quality to save with. Max of 95, passed directly to Pillow"))
array = confdef.add_def('trigger', shconf.TableArrayDef(
array = confdef.add_def('trigger', shconf.DictListDef(
helptext="Array of triggers that will use all cameras"))
array.add_def('hour', shconf.StringDef())
array.add_def('minute', shconf.StringDef())
@ -57,7 +57,7 @@ class PiCamPlugin(shepherd.plugin.Plugin):
self.hooks = pluginInterface.hooks
self.root_dir = os.path.expanduser(pluginInterface.coreconfig["root_dir"])
self.id = pluginInterface.coreconfig["id"]
self.id = pluginInterface.coreconfig["name"]
self.interface.register_hook("pre_cam")
self.interface.register_hook("post_cam")
@ -70,7 +70,7 @@ class PiCamPlugin(shepherd.plugin.Plugin):
# Seconds to wait for exposure and white balance auto-adjust to stabilise
self.stabilise_delay = 3
if self.config["save_directory"] is "":
if self.config["save_directory"] == "":
self.save_directory = os.path.join(self.root_dir, "picamera")
else:
self.save_directory = self.config["save_directory"]
@ -130,7 +130,6 @@ class PiCamPlugin(shepherd.plugin.Plugin):
overlay.putalpha(128)
return overlay
def camera_job(self):
self.hooks.pre_cam()

@ -161,7 +161,7 @@ class Bucket():
class UploaderPlugin(shepherd.plugin.Plugin):
@staticmethod
def define_config(confdef):
dests = confdef.add_def('destination', shconf.TableArrayDef())
dests = confdef.add_def('destination', shconf.DictListDef())
dests.add_def('name', shconf.StringDef())
dests.add_def('protocol', shconf.StringDef())
dests.add_def('address', shconf.StringDef(optional=True))
@ -174,7 +174,7 @@ class UploaderPlugin(shepherd.plugin.Plugin):
dests.add_def('add_id_to_path', shconf.BoolDef(
default=True, optional=True))
buckets = confdef.add_def('bucket', shconf.TableArrayDef())
buckets = confdef.add_def('bucket', shconf.DictListDef())
buckets.add_def('name', shconf.StringDef())
buckets.add_def('open_link_on_new', shconf.BoolDef())
buckets.add_def('opportunistic', shconf.BoolDef(
@ -190,7 +190,7 @@ class UploaderPlugin(shepherd.plugin.Plugin):
self.hooks = pluginInterface.hooks
self.root_dir = os.path.expanduser(pluginInterface.coreconfig["root_dir"])
self.id = pluginInterface.coreconfig["id"]
self.id = pluginInterface.coreconfig["name"]
print("Uploader config:")
print(self.config)

@ -29,11 +29,15 @@ CameraPort = namedtuple(
'CameraPort', ['usbPath', 'devicePath'])
# Short wrapper to allow use in a ``with`` context
class VideoCaptureCtx():
def __init__(self, *args, **kwargs):
self.capture_dev = cv2.VideoCapture(*args, **kwargs)
def __enter__(self):
return self.capture_dev
def __exit__(self, *args):
self.capture_dev.release()
@ -116,13 +120,13 @@ class USBCamPlugin(shepherd.plugin.Plugin):
confdef.add_def('stabilise_delay', shconf.IntDef(default=5, minval=1, maxval=30, optional=True,
helptext="Number of seconds to wait after starting each camera for exposure and white balance to settle"))
array = confdef.add_def('trigger', shconf.TableArrayDef(
array = confdef.add_def('trigger', shconf.DictListDef(
helptext="Array of triggers that will use all cameras"))
array.add_def('hour', shconf.StringDef())
array.add_def('minute', shconf.StringDef())
array.add_def('second', shconf.StringDef(default="0", optional=True))
camarray = confdef.add_def('camera', shconf.TableArrayDef(
camarray = confdef.add_def('camera', shconf.DictListDef(
helptext="List of cameras to try and connect to. Multiple ports may be listed, and any not connected will be skipped on each trigger."))
camarray.add_def('name', shconf.StringDef(default="", optional=False,
helptext="Name of camera, appended to filename and added to overlay"))
@ -137,7 +141,7 @@ class USBCamPlugin(shepherd.plugin.Plugin):
self.hooks = pluginInterface.hooks
self.root_dir = os.path.expanduser(pluginInterface.coreconfig["root_dir"])
self.id = pluginInterface.coreconfig["id"]
self.id = pluginInterface.coreconfig["name"]
self.interface.register_hook("pre_cam")
self.interface.register_hook("post_cam")
@ -150,7 +154,7 @@ class USBCamPlugin(shepherd.plugin.Plugin):
self.gstlock = threading.Lock()
if self.config["save_directory"] is "":
if self.config["save_directory"] == "":
self.save_directory = os.path.join(self.root_dir, "usbcamera")
else:
self.save_directory = self.config["save_directory"]
@ -237,7 +241,7 @@ class USBCamPlugin(shepherd.plugin.Plugin):
if self.config["append_id"]:
image_filename = image_filename + " " + self.id
if camera_name is not "":
if camera_name != "":
image_filename = image_filename+" "+camera_name
image_filename = image_filename + ".jpg"
image_filename = os.path.join(self.save_directory, image_filename)
@ -264,7 +268,6 @@ class USBCamPlugin(shepherd.plugin.Plugin):
size = get_largest_resolution(fmts["MJPG"])
set_camera_format_opencv(vidcap, "MJPG", size[0], size[1])
# stream only starts after first grab
print("Starting cam")
@ -285,7 +288,6 @@ class USBCamPlugin(shepherd.plugin.Plugin):
# print("Reading again")
# read_flag, frame2 = vidcap.read()
if read_flag:
self._process_image(frame, camera_name)
# self._process_image(frame2, camera_name+"(2)")

@ -130,11 +130,11 @@ def save_jobs():
raise Exception("Could not save scheduler job " +
job.id+" - Trigger is not a CronTrigger")
saved_jobs.append(job.id)
if hasattr(job,"next_run_time"):
if next_job_time is not None:
if job.next_run_time < next_job_time:
next_job_time = job.next_run_time
else:
next_job_time = job.next_run_time
with open(joblist_path+".writing", 'w+') as f:
@ -189,8 +189,8 @@ def _jobs_changed(event):
print(retval)
if retval == alarm_str:
if is_raspberry_pi():
print("Shutting down in 1 minute")
time.sleep(60)
print("Shutting down in 2 minutes")
time.sleep(120)
subprocess.run(["shutdown","now"])
else:

@ -0,0 +1,38 @@
[shepherd]
hostname = "DPIRD-test"
id = "DPIRD-test"
plugin_dir = "/home/pi/plugins/"
plugins = ["scout", "picam", "uploader", "mothtrap"]
root_dir = "/home/pi/"
conf_edit_path = "/boot/shepherd.toml"
control_server = "api.shepherd.distreon.net"
api_key = "v2EgvYzx79c8fCP4P7jlWxTZ3pc"
[scout]
boardver = "3"
serialport = "/dev/ttyS0"
[uploader]
[[uploader.destination]]
name = "agricSFTP"
protocol = "sftp"
address = "agric.files.distreon.net"
port = 2222
path = "/mothtraps"
username = "agric"
password = "asherhaze"
[[uploader.bucket]]
name = "imageupload"
open_link_on_new = true
keep_copy = false
destination = "agricSFTP"
[picam]
upload_images = true
upload_bucket = "imageupload"
[[picam.trigger]]
hour = "*"
minute ="*/15"
second = "0"
[mothtrap]
servo_open_pulse = 900
servo_closed_pulse = 2100
servo_open_time = 3
# shepherd_message: Successfully applied this config at:2020-03-29 18:29:28.566836

@ -0,0 +1,50 @@
[shepherd]
hostname = "DPIRD-test"
id = "DPIRD-test"
plugin_dir = "/home/pi/plugins/"
plugins = ["scout", "usbcam", "uploader", "flytrap"]
root_dir = "/home/pi/"
conf_edit_path = "/boot/shepherd.toml"
control_server = "api.shepherd.distreon.net"
api_key = "v2EgvYzx79c8fCP4P7jlWxTZ3pc"
[scout]
boardver = "3"
serialport = "/dev/ttyS0"
[uploader]
[[uploader.destination]]
name = "agricSFTP"
protocol = "sftp"
address = "agric.files.distreon.net"
port = 2222
path = "/mothtraps"
username = "agric"
password = "asherhaze"
[[uploader.bucket]]
name = "imageupload"
open_link_on_new = true
keep_copy = false
destination = "agricSFTP"
[usbcam]
upload_images = true
upload_bucket = "imageupload"
[[usbcam.camera]]
name = "USB1"
usb_port = "1.2"
[[usbcam.camera]]
name = "USB2"
usb_port = "1.3"
[[usbcam.camera]]
name = "USB3"
usb_port = "1.1"
[[usbcam.camera]]
name = "USB"
usb_port = "*"
[[usbcam.trigger]]
hour = "*"
minute ="0"
second = "0"
[flytrap]
servo_open_pulse = 2100
servo_closed_pulse = 900
servo_open_time = 3
# shepherd_message: Successfully applied this config at:2019-12-16 00:59:30.985447
Loading…
Cancel
Save