diff --git a/sensors/robotics/sensorhub-driver-puppypi/README.md b/sensors/robotics/sensorhub-driver-puppypi/README.md
new file mode 100644
index 000000000..322d7e661
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/README.md
@@ -0,0 +1,50 @@
+# [NAME]
+
+Sensor adapter for [NAME].
+
+## Configuration
+
+Configuring the sensor requires:
+Select ```Sensors``` from the left hand accordion control and right click for context sensitive menu in accordion control
+- **Module Name:** A name for the instance of the driver
+- **Serial Number:** The platforms serial number, or a unique identifier
+- **Auto Start:** Check the box to start this module when OSH node is launched
+
+Storage:
+Select ```Storage``` from the left hand accordion control and right click for context sensitive menu in accordion control
+Use a ```Real-Time Stream Storage Module``` providing the sensor module as the
+- **Data Source ID:** Select the identifier for the storage module create in configuring sensor step,
+use looking glass to select it from list of know sensor modules
+- **Auto Start:** Check the box to start this module when OSH node is launched
+- **Process Events:** Check the box if you want events to be stored as new records.
+
+And then configure the
+- **Storage Config** using a ```Perst Record Storage``` instance providing the
+ - **Storage Path** as the location where the OSH records are to be stored.
+
+SOS Service:
+Select ```Services``` from the left hand accordion control, then Offerings, then the **+**
+symbol to add a new offering.
+Provide the following:
+- **Name:** A name for the offering
+- **Description:** A description of the offering
+- **StorageId:** Select the identifier for the storage module create in previous step,
+ use looking glass to select it from list of know storage modules
+- **SensorId:** Select the identifier for the storage module create in configuring sensor step,
+ use looking glass to select it from list of know sensor modules
+- **Enable:** Check the box to enable this offering
+
+## Sample Requests
+
+The following are a list of example requests and their respective responses.
+The **IP ADDRESS** and **PORT** will need to be specified and point to the instance
+of the OpenSensorHub node serving the data.
+
+### [Observed Property] Request
+- **HTTP**
+ - http://[IP ADDRESS]:[PORT]/sensorhub/sos?service=SOS&version=2.0&request=GetResult&offering=[URN]&observedProperty=[OBSERVED_PROPERTY]&temporalFilter=phenomenonTime,[START_TIME]/[END_TIME]&replaySpeed=1&responseFormat=application/json
+
+Response:
+```
+
+```
\ No newline at end of file
diff --git a/sensors/robotics/sensorhub-driver-puppypi/build.gradle b/sensors/robotics/sensorhub-driver-puppypi/build.gradle
new file mode 100644
index 000000000..540ac8a0a
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/build.gradle
@@ -0,0 +1,38 @@
+description = 'Puppy Pi Driver'
+ext.details = "Driver for Puppy Pi outputs and controls"
+version = '1.0.0'
+
+dependencies {
+ implementation 'org.sensorhub:sensorhub-core:' + oshCoreVersion
+// implementation project(':sensorhub-service-video')
+ testImplementation('junit:junit:4.13.1')
+ implementation project(':sensorhub-driver-videocam')
+}
+
+// exclude tests requiring connection to the sensor
+// these have to be run manually
+// If tests are to be excluded list them here as follows
+// exclude '**/TestNameClass.class'
+test {
+ useJUnit()
+}
+
+// add info to OSGi manifest
+osgi {
+ manifest {
+ attributes ('Bundle-Vendor': 'Botts Inc')
+ attributes ('Bundle-Activator': 'com.sample.impl.sensor.puppypi.Activator')
+ }
+}
+
+// add info to maven pom
+ext.pom >>= {
+ developers {
+ developer {
+ id 'pkhaisman'
+ name 'Philip Khaisman'
+ organization 'Botts Innovative Research, Inc.'
+ organizationUrl 'http://www.botts-inc.com'
+ }
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Activator.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Activator.java
new file mode 100644
index 000000000..bc37dc345
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Activator.java
@@ -0,0 +1,6 @@
+package com.sample.impl.sensor.puppypi;
+
+import org.sensorhub.utils.OshBundleActivator;
+
+public class Activator extends OshBundleActivator {
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Config.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Config.java
new file mode 100644
index 000000000..1000f1d98
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Config.java
@@ -0,0 +1,42 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi;
+
+import org.sensorhub.api.config.DisplayInfo;
+import org.sensorhub.api.sensor.SensorConfig;
+
+/**
+ * Configuration settings for the {@link Sensor} driver exposed via the OpenSensorHub Admin panel.
+ *
+ * Configuration settings take the form of
+ *
+ * DisplayInfo(desc="Description of configuration field to show in UI")
+ * public Type configOption;
+ *
+ *
+ * Containing an annotation describing the setting and if applicable its range of values
+ * as well as a public access variable of the given Type
+ *
+ * @author your_name
+ * @since date
+ */
+public class Config extends SensorConfig {
+
+ /**
+ * The unique identifier for the configured sensor (or sensor platform).
+ */
+ @DisplayInfo.Required
+ @DisplayInfo(desc = "Serial number or unique identifier")
+ public String serialNumber = "sensor001";
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Descriptor.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Descriptor.java
new file mode 100644
index 000000000..71c9e3e12
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Descriptor.java
@@ -0,0 +1,49 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+ ******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi;
+
+import org.sensorhub.api.module.IModule;
+import org.sensorhub.api.module.IModuleProvider;
+import org.sensorhub.api.module.ModuleConfig;
+import org.sensorhub.impl.module.JarModuleProvider;
+
+/**
+ * Descriptor classes provide access to informative data on the OpenSensorHub driver
+ *
+ * @author your_name
+ * @since date
+ */
+public class Descriptor extends JarModuleProvider implements IModuleProvider {
+
+ /**
+ * Retrieves the class implementing the OpenSensorHub interface necessary to
+ * perform SOS/SPS/SOS-T operations.
+ *
+ * @return The class used to interact with the sensor/sensor platform.
+ */
+ public Class extends IModule>> getModuleClass() {
+
+ return Sensor.class;
+ }
+
+ /**
+ * Identifies the class used to configure this driver
+ *
+ * @return The java class used to exposing configuration settings for the driver.
+ */
+ public Class extends ModuleConfig> getModuleConfigClass() {
+
+ return Config.class;
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Sensor.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Sensor.java
new file mode 100644
index 000000000..c0e0a8a55
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/Sensor.java
@@ -0,0 +1,99 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+ ******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi;
+
+import com.sample.impl.sensor.puppypi.controls.MovementControl;
+import com.sample.impl.sensor.puppypi.outputs.BatteryOutput;
+import com.sample.impl.sensor.puppypi.outputs.PositionOutput;
+import com.sample.impl.sensor.puppypi.outputs.VideoOutput;
+import org.sensorhub.api.common.SensorHubException;
+import org.sensorhub.impl.sensor.AbstractSensorModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sensor driver providing sensor description, output registration, initialization and shutdown of driver and outputs.
+ *
+ * @author your_name
+ * @since date
+ */
+public class Sensor extends AbstractSensorModule {
+
+ private static final Logger logger = LoggerFactory.getLogger(Sensor.class);
+
+ BatteryOutput batteryOutput;
+ VideoOutput videoOutput;
+ PositionOutput positionOutput;
+ MovementControl movementControl;
+
+ @Override
+ public void doInit() throws SensorHubException {
+
+ super.doInit();
+
+ // Generate identifiers
+ // generateUniqueID("[URN]", config.serialNumber);
+ this.uniqueID = "urn:osh:sensor:puppypi"; // todo change to include serial number
+ generateXmlID("[XML-PREFIX]", config.serialNumber);
+
+ // Outputs
+ batteryOutput = new BatteryOutput(this);
+ videoOutput = new VideoOutput(this);
+ positionOutput = new PositionOutput(this);
+
+ addOutput(batteryOutput, false);
+ addOutput(videoOutput, false);
+ addOutput(positionOutput, false);
+
+ batteryOutput.doInit();
+ videoOutput.doInit();
+ positionOutput.doInit();
+
+ // Control streams
+// movementControl = new MovementControl(this);
+// addControlInput(movementControl);
+// movementControl.doInit();
+ }
+
+ @Override
+ public void doStart() throws SensorHubException {
+
+ if (null != batteryOutput) {
+
+ // Allocate necessary resources and start outputs
+// batteryOutput.doStart();
+ }
+
+ // TODO: Perform other startup procedures
+ }
+
+ @Override
+ public void doStop() throws SensorHubException {
+
+ if (null != batteryOutput) {
+
+// batteryOutput.doStop();
+ }
+
+ // TODO: Perform other shutdown procedures
+ }
+
+ @Override
+ public boolean isConnected() {
+
+ // Determine if sensor is connected
+// return batteryOutput.isAlive();
+ return true;
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/controls/MovementControl.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/controls/MovementControl.java
new file mode 100644
index 000000000..05d872fb4
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/controls/MovementControl.java
@@ -0,0 +1,60 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+ The Initial Developer is Botts Innovative Research Inc. Portions created by the Initial
+ Developer are Copyright (C) 2014 the Initial Developer. All Rights Reserved.
+ ******************************* END LICENSE BLOCK ***************************/
+
+package com.sample.impl.sensor.puppypi.controls;
+
+import net.opengis.swe.v20.*;
+import org.sensorhub.impl.sensor.AbstractSensorControl;
+import org.sensorhub.api.command.CommandException;
+import org.vast.swe.SWEConstants;
+import org.vast.swe.SWEHelper;
+import com.sample.impl.sensor.puppypi.Sensor;
+import org.vast.swe.helper.GeoPosHelper;
+
+
+public class MovementControl extends AbstractSensorControl {
+ private static final String SENSOR_CONTROL_NAME = "Puppy Pi Control";
+ private static final String SENSOR_CONTROL_LABEL = "puppy pi control";
+ private static final String SENSOR_CONTROL_DESCRIPTION = "Controls movement of the puppy pi";
+
+ DataComponent commandStruct;
+
+ public MovementControl(Sensor parentSensor) {
+ super("MovementControl", parentSensor);
+ }
+
+
+ @Override
+ public DataComponent getCommandDescription() {
+ return commandStruct;
+ }
+
+
+ public void doInit() {
+ GeoPosHelper sweFactory = new GeoPosHelper();
+
+ commandStruct = sweFactory.createVelocityVector("m/s")
+ .name("velocity")
+ .label("Velocity")
+ .definition(SWEHelper.getPropertyUri("PlatformVelocity"))
+ .description("xxx")
+ .refFrame(SWEConstants.REF_FRAME_ENU)
+ .build();
+ }
+
+ @Override
+ protected boolean execCommand(DataBlock command) {
+ DataComponent commandData = commandStruct.copy();
+ commandData.setData(command);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/BatteryOutput.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/BatteryOutput.java
new file mode 100644
index 000000000..0da73f384
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/BatteryOutput.java
@@ -0,0 +1,105 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+ ******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi.outputs;
+
+import net.opengis.swe.v20.DataBlock;
+import net.opengis.swe.v20.DataComponent;
+import net.opengis.swe.v20.DataEncoding;
+import net.opengis.swe.v20.DataRecord;
+import org.sensorhub.api.data.DataEvent;
+import org.sensorhub.impl.sensor.AbstractSensorOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vast.swe.helper.GeoPosHelper;
+import com.sample.impl.sensor.puppypi.Sensor;
+
+/**
+ * Output specification and provider for {@link Sensor}.
+ *
+ * @author your_name
+ * @since date
+ */
+public class BatteryOutput extends AbstractSensorOutput {
+
+ private static final String SENSOR_OUTPUT_NAME = "BatteryVoltage";
+ private static final String SENSOR_OUTPUT_LABEL = "Battery Sensor";
+ private static final String SENSOR_OUTPUT_DESCRIPTION = "Current voltage of battery pack";
+
+ private static final Logger logger = LoggerFactory.getLogger(BatteryOutput.class);
+
+ private DataRecord dataStruct;
+ private DataEncoding dataEncoding;
+
+ /**
+ * Constructor
+ *
+ * @param parentSensor Sensor driver providing this output
+ */
+ public BatteryOutput(Sensor parentSensor) {
+
+ super(SENSOR_OUTPUT_NAME, parentSensor);
+
+ logger.debug("Output created");
+ }
+
+ /**
+ * Initializes the data structure for the output, defining the fields, their ordering,
+ * and data types.
+ */
+ public void doInit() {
+
+ logger.debug("Initializing Output");
+
+ GeoPosHelper sweFactory = new GeoPosHelper();
+
+ // TODO: Create data record description
+ dataStruct = sweFactory.createRecord()
+ .name(SENSOR_OUTPUT_NAME)
+ .label(SENSOR_OUTPUT_LABEL)
+ .description(SENSOR_OUTPUT_DESCRIPTION)
+ .definition(sweFactory.getPropertyUri(SENSOR_OUTPUT_NAME))
+ .addField("SampleTime",
+ sweFactory.createTime()
+ .asSamplingTimeIsoUTC()
+ .build())
+ .addField("Voltage",
+ sweFactory.createQuantity()
+ .name("Voltage")
+ .label("Voltage")
+ .definition("http://qudt.org/vocab/quantitykind/Voltage")
+ .description("Current reported battery pack voltage")
+ .uom("V")
+ .build())
+ .build();
+
+ dataEncoding = sweFactory.newTextEncoding(",", "\n");
+
+ logger.debug("Initializing Output Complete");
+ }
+
+ @Override
+ public DataComponent getRecordDescription() {
+ return dataStruct;
+ }
+
+ @Override
+ public DataEncoding getRecommendedEncoding() {
+ return dataEncoding;
+ }
+
+ @Override
+ public double getAverageSamplingPeriod() {
+ return Double.NaN;
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/PositionOutput.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/PositionOutput.java
new file mode 100644
index 000000000..ad844f775
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/PositionOutput.java
@@ -0,0 +1,95 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+ ******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi.outputs;
+
+import net.opengis.swe.v20.DataBlock;
+import net.opengis.swe.v20.DataComponent;
+import net.opengis.swe.v20.DataEncoding;
+import net.opengis.swe.v20.DataRecord;
+import org.sensorhub.api.data.DataEvent;
+import org.sensorhub.impl.sensor.AbstractSensorOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vast.data.TextEncodingImpl;
+import org.vast.swe.SWEHelper;
+import org.vast.swe.helper.GeoPosHelper;
+import com.sample.impl.sensor.puppypi.Sensor;
+
+/**
+ * Output specification and provider for {@link Sensor}.
+ *
+ * @author your_name
+ * @since date
+ */
+public class PositionOutput extends AbstractSensorOutput {
+
+ private static final String SENSOR_OUTPUT_NAME = "Position";
+ private static final String SENSOR_OUTPUT_LABEL = "Position";
+ private static final String SENSOR_OUTPUT_DESCRIPTION = "Coordinates of the puppy pi";
+
+ private static final Logger logger = LoggerFactory.getLogger(PositionOutput.class);
+
+ private DataRecord dataStruct;
+ private DataEncoding dataEncoding;
+
+ /**
+ * Constructor
+ *
+ * @param parentSensor Sensor driver providing this output
+ */
+ public PositionOutput(Sensor parentSensor) {
+
+ super(SENSOR_OUTPUT_NAME, parentSensor);
+
+ logger.debug("Output created");
+ }
+
+ /**
+ * Initializes the data structure for the output, defining the fields, their ordering,
+ * and data types.
+ */
+ public void doInit() {
+ GeoPosHelper geoFac = new GeoPosHelper();
+ SWEHelper sweHelper = new SWEHelper();
+ dataEncoding = new TextEncodingImpl(",","/n");
+
+ dataStruct = geoFac.createRecord()
+ .name(SENSOR_OUTPUT_NAME)
+ .label(SENSOR_OUTPUT_LABEL)
+ .description(SENSOR_OUTPUT_DESCRIPTION)
+ .definition(sweHelper.getPropertyUri(SENSOR_OUTPUT_NAME))
+ .addField("SampleTime",
+ sweHelper.createTime()
+ .asSamplingTimeIsoUTC()
+ .build())
+ .addField("Position",
+ geoFac.newLocationVectorLLA(SWEHelper.getPropertyUri("location")))
+ .build();
+ }
+
+ @Override
+ public DataComponent getRecordDescription() {
+ return dataStruct;
+ }
+
+ @Override
+ public DataEncoding getRecommendedEncoding() {
+ return dataEncoding;
+ }
+
+ @Override
+ public double getAverageSamplingPeriod() {
+ return Double.NaN;
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/VideoOutput.java b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/VideoOutput.java
new file mode 100644
index 000000000..737bdaf76
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/java/com/sample/impl/sensor/puppypi/outputs/VideoOutput.java
@@ -0,0 +1,140 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2020-2021 Botts Innovative Research, Inc. All Rights Reserved.
+
+ ******************************* END LICENSE BLOCK ***************************/
+package com.sample.impl.sensor.puppypi.outputs;
+
+import net.opengis.swe.v20.*;
+import org.sensorhub.api.data.DataEvent;
+import org.sensorhub.impl.sensor.AbstractSensorOutput;
+import org.sensorhub.impl.sensor.videocam.VideoCamHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vast.cdm.common.CDMException;
+import org.vast.data.JSONEncodingImpl;
+import org.vast.swe.SWEHelper;
+import org.vast.swe.helper.GeoPosHelper;
+import com.sample.impl.sensor.puppypi.Sensor;
+import org.vast.swe.helper.RasterHelper;
+
+import javax.xml.crypto.Data;
+
+/**
+ * Output specification and provider for {@link Sensor}.
+ *
+ * @author your_name
+ * @since date
+ */
+public class VideoOutput extends AbstractSensorOutput {
+
+ private static final String SENSOR_OUTPUT_NAME = "Video";
+ private static final String SENSOR_OUTPUT_LABEL = "Puppy Pi Video";
+ private static final String SENSOR_OUTPUT_DESCRIPTION = "Video stream from puppy pi camera";
+ private static final Integer VIDEO_FRAME_WIDTH = 640;
+ private static final Integer VIDEO_FRAME_HEIGHT = 480;
+ private static final String CODEC_MJPEG = "JPEG";
+
+ private static final Logger logger = LoggerFactory.getLogger(VideoOutput.class);
+
+ private DataComponent dataStruct;
+ private DataEncoding dataEncoding;
+
+ /**
+ * Constructor
+ *
+ * @param parentSensor Sensor driver providing this output
+ */
+ public VideoOutput(Sensor parentSensor) {
+
+ super(SENSOR_OUTPUT_NAME, parentSensor);
+
+ logger.debug("Output created");
+ }
+
+ /**
+ * Initializes the data structure for the output, defining the fields, their ordering,
+ * and data types.
+ */
+ public void doInit() {
+
+ logger.debug("Initializing video output.");
+
+ VideoCamHelper sweHelper = new VideoCamHelper();
+
+ // build output structure
+ DataStream videoStream = sweHelper.newVideoOutputMJPEG(getName(), VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT);
+ // todo why did i add this?
+ // videoStream.setEncoding(new JSONEncodingImpl());
+ dataStruct = videoStream.getElementType();
+ dataEncoding = videoStream.getEncoding();
+
+ System.out.println("***");
+ System.out.println(dataStruct.toString());
+
+// RasterHelper sweHelper = new RasterHelper();
+// dataStruct = sweHelper.createRecord()
+// .name(SENSOR_OUTPUT_NAME)
+// .label(SENSOR_OUTPUT_LABEL)
+// .description(SENSOR_OUTPUT_DESCRIPTION)
+// .definition(SWEHelper.getPropertyUri("VideoFrame"))
+// .addField("sampleTime", sweHelper.createTime()
+// .asSamplingTimeIsoUTC()
+// .label("Sample Time")
+// .description("Time of data collection"))
+// .addField("phenomenonTime", sweHelper.createTime()
+// .asPhenomenonTimeIsoUTC()
+// .label("Phenomenon Time")
+// .description("Time reported by sensor"))
+// .addField("img", sweHelper.newRgbImage(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT, DataType.BYTE))
+// .build();
+//
+// BinaryEncoding dataEnc = sweHelper.newBinaryEncoding(ByteOrder.BIG_ENDIAN, ByteEncoding.RAW);
+//
+// BinaryComponent sampleTimeEnc = sweHelper.newBinaryComponent();
+// sampleTimeEnc.setRef("/" + dataStruct.getComponent(0).getName());
+// sampleTimeEnc.setCdmDataType(DataType.DOUBLE);
+// dataEnc.addMemberAsComponent(sampleTimeEnc);
+//
+// BinaryComponent phenomenonTimeEnc = sweHelper.newBinaryComponent();
+// phenomenonTimeEnc.setRef("/" + dataStruct.getComponent(1).getName());
+// phenomenonTimeEnc.setCdmDataType(DataType.DOUBLE);
+// dataEnc.addMemberAsComponent(phenomenonTimeEnc);
+//
+// BinaryBlock compressedBlock = sweHelper.newBinaryBlock();
+// compressedBlock.setRef("/" + dataStruct.getComponent(2).getName());
+// compressedBlock.setCompression(CODEC_MJPEG);
+// dataEnc.addMemberAsBlock(compressedBlock);
+//
+// try {
+// SWEHelper.assignBinaryEncoding(dataStruct, dataEnc);
+// } catch (CDMException e) {
+// throw new RuntimeException("Invalid binary encoding configuration", e);
+// }
+//
+// this.dataEncoding = dataEnc;
+ }
+
+ @Override
+ public DataComponent getRecordDescription() {
+ return dataStruct;
+ }
+
+ @Override
+ public DataEncoding getRecommendedEncoding() {
+ return dataEncoding;
+ }
+
+ @Override
+ public double getAverageSamplingPeriod() {
+ return Double.NaN;
+ }
+}
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/main/resources/META-INF/services/org.sensorhub.api.module.IModuleProvider b/sensors/robotics/sensorhub-driver-puppypi/src/main/resources/META-INF/services/org.sensorhub.api.module.IModuleProvider
new file mode 100644
index 000000000..a93e716b3
--- /dev/null
+++ b/sensors/robotics/sensorhub-driver-puppypi/src/main/resources/META-INF/services/org.sensorhub.api.module.IModuleProvider
@@ -0,0 +1 @@
+com.sample.impl.sensor.puppypi.Descriptor
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/test/java/empty b/sensors/robotics/sensorhub-driver-puppypi/src/test/java/empty
new file mode 100644
index 000000000..e69de29bb
diff --git a/sensors/robotics/sensorhub-driver-puppypi/src/test/resources/empty b/sensors/robotics/sensorhub-driver-puppypi/src/test/resources/empty
new file mode 100644
index 000000000..e69de29bb