mirror of
https://github.com/jlengrand/therobottle.git
synced 2026-03-10 08:41:18 +00:00
Start from robottle with Helidon
This commit is contained in:
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
target/*
|
||||||
59
.gitignore
vendored
Normal file
59
.gitignore
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
.DS_Store
|
||||||
|
.idea/shelf
|
||||||
|
/android.tests.dependencies
|
||||||
|
/confluence/target
|
||||||
|
/dependencies/repo
|
||||||
|
/dist
|
||||||
|
/local
|
||||||
|
/gh-pages
|
||||||
|
/ideaSDK
|
||||||
|
/clionSDK
|
||||||
|
/android-studio/sdk
|
||||||
|
out/
|
||||||
|
/tmp
|
||||||
|
workspace.xml
|
||||||
|
*.versionsBackup
|
||||||
|
/idea/testData/debugger/tinyApp/classes*
|
||||||
|
/jps-plugin/testData/kannotator
|
||||||
|
/js/js.translator/testData/out/
|
||||||
|
/js/js.translator/testData/out-min/
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
!**/src/**/build
|
||||||
|
!**/test/**/build
|
||||||
|
*.iml
|
||||||
|
!**/testData/**/*.iml
|
||||||
|
.idea/libraries/Gradle*.xml
|
||||||
|
.idea/libraries/Maven*.xml
|
||||||
|
.idea/artifacts/PILL_*.xml
|
||||||
|
.idea/artifacts/KotlinPlugin.xml
|
||||||
|
.idea/modules
|
||||||
|
.idea/runConfigurations/JPS_*.xml
|
||||||
|
.idea/runConfigurations/PILL_*.xml
|
||||||
|
.idea/libraries
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/inspectionProfiles/profiles_settings.xml
|
||||||
|
.idea/.name
|
||||||
|
.idea/artifacts/dist_auto_*
|
||||||
|
.idea/artifacts/dist.xml
|
||||||
|
.idea/artifacts/ideaPlugin.xml
|
||||||
|
.idea/artifacts/kotlinc.xml
|
||||||
|
.idea/artifacts/kotlin_compiler_jar.xml
|
||||||
|
.idea/artifacts/kotlin_plugin_jar.xml
|
||||||
|
.idea/artifacts/kotlin_jps_plugin_jar.xml
|
||||||
|
.idea/artifacts/kotlin_daemon_client_jar.xml
|
||||||
|
.idea/artifacts/kotlin_imports_dumper_compiler_plugin_jar.xml
|
||||||
|
.idea/artifacts/kotlin_main_kts_jar.xml
|
||||||
|
.idea/artifacts/kotlin_compiler_client_embeddable_jar.xml
|
||||||
|
.idea/artifacts/kotlin_reflect_jar.xml
|
||||||
|
kotlin-ultimate/
|
||||||
|
node_modules/
|
||||||
|
.rpt2_cache/
|
||||||
|
libraries/tools/kotlin-test-js-runner/lib/
|
||||||
|
libraries/tools/kotlin-source-map-loader/lib/
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
*.o
|
||||||
|
target
|
||||||
19
.idea/$PRODUCT_WORKSPACE_FILE$
generated
Normal file
19
.idea/$PRODUCT_WORKSPACE_FILE$
generated
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="masterDetails">
|
||||||
|
<states>
|
||||||
|
<state key="ProjectJDKs.UI">
|
||||||
|
<settings>
|
||||||
|
<last-edited>1.8</last-edited>
|
||||||
|
<splitter-proportions>
|
||||||
|
<option name="proportions">
|
||||||
|
<list>
|
||||||
|
<option value="0.2" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</splitter-proportions>
|
||||||
|
</settings>
|
||||||
|
</state>
|
||||||
|
</states>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/deployment.xml
generated
Normal file
15
.idea/deployment.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PublishConfigData" autoUpload="Always" serverName="raspberry.local" autoUploadExternalChanges="true">
|
||||||
|
<serverData>
|
||||||
|
<paths name="raspberry.local">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping deploy="/" local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
</serverData>
|
||||||
|
<option name="myAutoUpload" value="ALWAYS" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
17
.idea/misc.xml
generated
Normal file
17
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ElmWorkspace">
|
||||||
|
<elmProjects />
|
||||||
|
<settings binDirPath="" />
|
||||||
|
</component>
|
||||||
|
<component name="MavenProjectsManager">
|
||||||
|
<option name="originalFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/classes" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/webServers.xml
generated
Normal file
15
.idea/webServers.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="WebServers">
|
||||||
|
<option name="servers">
|
||||||
|
<webServer id="d7eae866-388d-4485-8638-0714f981dbf8" name="raspberry.local" url="http://raspberrypi.local">
|
||||||
|
<fileTransfer host="raspberrypi.local" port="22" rootFolder="/home/pi/projects/therobottle" accessType="SFTP">
|
||||||
|
<advancedOptions>
|
||||||
|
<advancedOptions dataProtectionLevel="Private" passiveMode="true" shareSSLContext="true" />
|
||||||
|
</advancedOptions>
|
||||||
|
<option name="port" value="22" />
|
||||||
|
</fileTransfer>
|
||||||
|
</webServer>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
44
Dockerfile
Normal file
44
Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# 1st stage, build the app
|
||||||
|
FROM maven:3.5.4-jdk-9 as build
|
||||||
|
|
||||||
|
WORKDIR /helidon
|
||||||
|
|
||||||
|
# Create a first layer to cache the "Maven World" in the local repository.
|
||||||
|
# Incremental docker builds will always resume after that, unless you update
|
||||||
|
# the pom
|
||||||
|
ADD pom.xml .
|
||||||
|
RUN mvn package -DskipTests
|
||||||
|
|
||||||
|
# Do the Maven build!
|
||||||
|
# Incremental docker builds will resume here when you change sources
|
||||||
|
ADD src src
|
||||||
|
RUN mvn package -DskipTests
|
||||||
|
RUN echo "done!"
|
||||||
|
|
||||||
|
# 2nd stage, build the runtime image
|
||||||
|
FROM openjdk:8-jre-slim
|
||||||
|
WORKDIR /helidon
|
||||||
|
|
||||||
|
# Copy the binary built in the 1st stage
|
||||||
|
COPY --from=build /helidon/target/therobottle.jar ./
|
||||||
|
COPY --from=build /helidon/target/libs ./libs
|
||||||
|
|
||||||
|
CMD ["java", "-jar", "therobottle.jar"]
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
35
README.md
Normal file
35
README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Robottle
|
||||||
|
|
||||||
|
WIP: Don't expect any structure in there. As of now it's a collection of tryouts without particular shape
|
||||||
|
|
||||||
|
A raspberry based sensor to keep my wine cellar under control
|
||||||
|
|
||||||
|
## Hardware :
|
||||||
|
|
||||||
|
* Raspberry (starting with a Raspberry 1)
|
||||||
|
* Maybe Piface
|
||||||
|
* DHT11 4 pins
|
||||||
|
|
||||||
|
## Readings
|
||||||
|
|
||||||
|
|
||||||
|
http://www.circuitbasics.com/how-to-set-up-the-dht11-humidity-sensor-on-the-raspberry-pi/
|
||||||
|
http://sebi.io/general/2018/08/13/Developing-for-Raspberry-Pi.html
|
||||||
|
https://medium.com/@menchukanton/setup-intellij-idea-for-remote-debugging-java-code-on-a-raspberry-pi-6e9df09dfb95
|
||||||
|
http://wiringpi.com/download-and-install/
|
||||||
|
|
||||||
|
https://github.com/cory-johannsen/gradle-jni-example
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
[Julien Lengrand-Lambert](https://github.com/jlengrand)
|
||||||
|
|
||||||
|
|
||||||
|
pi/robottle
|
||||||
|
raspberrypi
|
||||||
|
|
||||||
|
ping raspberrypi.local
|
||||||
|
|
||||||
|
|
||||||
|
http://hirt.se/blog/?p=1116
|
||||||
|
https://github.com/fauna/faunadb-jvm/blob/master/docs/java.md
|
||||||
68
README_helidon.md
Normal file
68
README_helidon.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Helidon Quickstart MP Example
|
||||||
|
|
||||||
|
This example implements a simple Hello World REST service using MicroProfile.
|
||||||
|
|
||||||
|
## Build and run
|
||||||
|
|
||||||
|
With JDK8+
|
||||||
|
```bash
|
||||||
|
mvn package
|
||||||
|
java -jar target/therobottle.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
## Exercise the application
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -X GET http://localhost:8080/greet
|
||||||
|
{"message":"Hello World!"}
|
||||||
|
|
||||||
|
curl -X GET http://localhost:8080/greet/Joe
|
||||||
|
{"message":"Hello Joe!"}
|
||||||
|
|
||||||
|
curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting
|
||||||
|
|
||||||
|
curl -X GET http://localhost:8080/greet/Jose
|
||||||
|
{"message":"Hola Jose!"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Try health and metrics
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s -X GET http://localhost:8080/health
|
||||||
|
{"outcome":"UP",...
|
||||||
|
. . .
|
||||||
|
|
||||||
|
# Prometheus Format
|
||||||
|
curl -s -X GET http://localhost:8080/metrics
|
||||||
|
# TYPE base:gc_g1_young_generation_count gauge
|
||||||
|
. . .
|
||||||
|
|
||||||
|
# JSON Format
|
||||||
|
curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
|
||||||
|
{"base":...
|
||||||
|
. . .
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build the Docker Image
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t therobottle .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start the application with Docker
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -p 8080:8080 therobottle:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Exercise the application as described above
|
||||||
|
|
||||||
|
## Deploy the application to Kubernetes
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl cluster-info # Verify which cluster
|
||||||
|
kubectl get pods # Verify connectivity to cluster
|
||||||
|
kubectl create -f app.yaml # Deploy application
|
||||||
|
kubectl get service therobottle # Verify deployed service
|
||||||
|
```
|
||||||
50
app.yaml
Normal file
50
app.yaml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
kind: Service
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: therobottle
|
||||||
|
labels:
|
||||||
|
app: therobottle
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
selector:
|
||||||
|
app: therobottle
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
name: http
|
||||||
|
---
|
||||||
|
kind: Deployment
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: therobottle
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: therobottle
|
||||||
|
version: v1
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: therobottle
|
||||||
|
image: therobottle
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
---
|
||||||
87
pom.xml
Normal file
87
pom.xml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>io.helidon.applications</groupId>
|
||||||
|
<artifactId>helidon-mp</artifactId>
|
||||||
|
<version>1.4.0</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
<groupId>nl.lengrand</groupId>
|
||||||
|
<artifactId>therobottle</artifactId>
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<mainClass>nl.lengrand.therobottle.Main</mainClass>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||||
|
<artifactId>helidon-microprofile</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jersey.media</groupId>
|
||||||
|
<artifactId>jersey-media-json-binding</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss</groupId>
|
||||||
|
<artifactId>jandex</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.activation</groupId>
|
||||||
|
<artifactId>javax.activation-api</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-libs</id>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jboss.jandex</groupId>
|
||||||
|
<artifactId>jandex-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-index</id>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
29
src/main/c/Dht11Driver.c
Normal file
29
src/main/c/Dht11Driver.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include "../java/nl/lengrand/therobottle/driver/nl_lengrand_therobottle_driver_Dht11Driver.h"
|
||||||
|
#include "adafruit/Raspberry_Pi_2/pi_2_dht_read.h"
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_Dht11Driver_sayHello(JNIEnv *env, jobject thisObj) {
|
||||||
|
printf("Hello JNI!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jfloatArray JNICALL Java_Dht11Driver_getTemperatureAndHumidity(JNIEnv *env, jobject thisObj){
|
||||||
|
float humidity = 0, temperature = 0;
|
||||||
|
int sensor = 11; // Make those dynamic one day?
|
||||||
|
int pin = 4; // Make those dynamic one day?
|
||||||
|
int res = pi_2_dht_read(sensor, pin, &humidity, &temperature); // Might wanna do something with status one day
|
||||||
|
|
||||||
|
jfloat* values = (jfloat *) malloc(2*sizeof(jfloat));
|
||||||
|
values[0] = temperature;
|
||||||
|
values[1] = humidity;
|
||||||
|
|
||||||
|
jfloatArray outJNIArray = (*env)->NewFloatArray(env, 2);
|
||||||
|
if (NULL == outJNIArray) return NULL;
|
||||||
|
|
||||||
|
(*env)->SetFloatArrayRegion(env, outJNIArray, 0, 2, (const jfloat*)values);
|
||||||
|
return outJNIArray;
|
||||||
|
}
|
||||||
26
src/main/c/Makefile
Normal file
26
src/main/c/Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
JAVA_HOME=/usr/lib/jvm/java-11-openjdk-armhf
|
||||||
|
INCLUDES = -I. -I../java -Iadafruit/Raspberry_Pi_2 -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
|
||||||
|
HEADERS = ../java/nl/lengrand/therobottle/driver/nl_lengrand_therobottle_driver_Dht11Driver.h adafruit/common_dht_read.h adafruit/Raspberry_Pi_2/pi_2_mmio.h adafruit/Raspberry_Pi_2/pi_2_dht_read.h
|
||||||
|
FILES = adafruit/common_dht_read.c adafruit/Raspberry_Pi_2/pi_2_mmio.c adafruit/Raspberry_Pi_2/pi_2_dht_read.c Dht11Driver.c
|
||||||
|
OUT = libdht11
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
all: clean compileJava library
|
||||||
|
|
||||||
|
program: Dht11Driver.c
|
||||||
|
gcc -Wall $(INCLUDES) $(HEADERS) $(FILES) -o $(OUT)
|
||||||
|
|
||||||
|
library: Dht11Driver.c
|
||||||
|
gcc -shared -fPIC -o $(OUT).so $(INCLUDES) $(FILES)
|
||||||
|
|
||||||
|
move:
|
||||||
|
-cp $(OUT).so
|
||||||
|
|
||||||
|
compileJava:
|
||||||
|
-cd ../java/nl/lengrand/therobottle/driver;javac -h . Dht11Driver.java;cd -;
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm ../java/nl/lengrand/therobottle/driver/nl_lengrand_therobottle_driver_Dht11Driver.h
|
||||||
|
-rm -f $(OUT).so
|
||||||
|
-rm -f $(OUT)
|
||||||
1
src/main/c/README.md
Normal file
1
src/main/c/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
The code contained in the adafruit folder comes from https://github.com/adafruit/Adafruit_Python_DHT and will be used as driver
|
||||||
158
src/main/c/adafruit/Raspberry_Pi_2/pi_2_dht_read.c
Normal file
158
src/main/c/adafruit/Raspberry_Pi_2/pi_2_dht_read.c
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pi_2_dht_read.h"
|
||||||
|
#include "pi_2_mmio.h"
|
||||||
|
|
||||||
|
// This is the only processor specific magic value, the maximum amount of time to
|
||||||
|
// spin in a loop before bailing out and considering the read a timeout. This should
|
||||||
|
// be a high value, but if you're running on a much faster platform than a Raspberry
|
||||||
|
// Pi or Beaglebone Black then it might need to be increased.
|
||||||
|
#define DHT_MAXCOUNT 32000
|
||||||
|
|
||||||
|
// Number of bit pulses to expect from the DHT. Note that this is 41 because
|
||||||
|
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
|
||||||
|
// the data afterwards.
|
||||||
|
#define DHT_PULSES 41
|
||||||
|
|
||||||
|
int pi_2_dht_read(int type, int pin, float* humidity, float* temperature) {
|
||||||
|
// Validate humidity and temperature arguments and set them to zero.
|
||||||
|
if (humidity == NULL || temperature == NULL) {
|
||||||
|
return DHT_ERROR_ARGUMENT;
|
||||||
|
}
|
||||||
|
*temperature = 0.0f;
|
||||||
|
*humidity = 0.0f;
|
||||||
|
|
||||||
|
// Initialize GPIO library.
|
||||||
|
if (pi_2_mmio_init() < 0) {
|
||||||
|
return DHT_ERROR_GPIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the count that each DHT bit pulse is low and high.
|
||||||
|
// Make sure array is initialized to start at zero.
|
||||||
|
int pulseCounts[DHT_PULSES*2] = {0};
|
||||||
|
|
||||||
|
// Set pin to output.
|
||||||
|
pi_2_mmio_set_output(pin);
|
||||||
|
|
||||||
|
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
|
||||||
|
set_max_priority();
|
||||||
|
|
||||||
|
// Set pin high for ~500 milliseconds.
|
||||||
|
pi_2_mmio_set_high(pin);
|
||||||
|
sleep_milliseconds(500);
|
||||||
|
|
||||||
|
// The next calls are timing critical and care should be taken
|
||||||
|
// to ensure no unnecssary work is done below.
|
||||||
|
|
||||||
|
// Set pin low for ~20 milliseconds.
|
||||||
|
pi_2_mmio_set_low(pin);
|
||||||
|
busy_wait_milliseconds(20);
|
||||||
|
|
||||||
|
// Set pin at input.
|
||||||
|
pi_2_mmio_set_input(pin);
|
||||||
|
// Need a very short delay before reading pins or else value is sometimes still low.
|
||||||
|
for (volatile int i = 0; i < 50; ++i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for DHT to pull pin low.
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (pi_2_mmio_input(pin)) {
|
||||||
|
if (++count >= DHT_MAXCOUNT) {
|
||||||
|
// Timeout waiting for response.
|
||||||
|
set_default_priority();
|
||||||
|
return DHT_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record pulse widths for the expected result bits.
|
||||||
|
for (int i=0; i < DHT_PULSES*2; i+=2) {
|
||||||
|
// Count how long pin is low and store in pulseCounts[i]
|
||||||
|
while (!pi_2_mmio_input(pin)) {
|
||||||
|
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
|
||||||
|
// Timeout waiting for response.
|
||||||
|
set_default_priority();
|
||||||
|
return DHT_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Count how long pin is high and store in pulseCounts[i+1]
|
||||||
|
while (pi_2_mmio_input(pin)) {
|
||||||
|
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
|
||||||
|
// Timeout waiting for response.
|
||||||
|
set_default_priority();
|
||||||
|
return DHT_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done with timing critical code, now interpret the results.
|
||||||
|
|
||||||
|
// Drop back to normal priority.
|
||||||
|
set_default_priority();
|
||||||
|
|
||||||
|
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
|
||||||
|
// Ignore the first two readings because they are a constant 80 microsecond pulse.
|
||||||
|
uint32_t threshold = 0;
|
||||||
|
for (int i=2; i < DHT_PULSES*2; i+=2) {
|
||||||
|
threshold += pulseCounts[i];
|
||||||
|
}
|
||||||
|
threshold /= DHT_PULSES-1;
|
||||||
|
|
||||||
|
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
|
||||||
|
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
|
||||||
|
// then it must be a ~70us 1 pulse.
|
||||||
|
uint8_t data[5] = {0};
|
||||||
|
for (int i=3; i < DHT_PULSES*2; i+=2) {
|
||||||
|
int index = (i-3)/16;
|
||||||
|
data[index] <<= 1;
|
||||||
|
if (pulseCounts[i] >= threshold) {
|
||||||
|
// One bit for long pulse.
|
||||||
|
data[index] |= 1;
|
||||||
|
}
|
||||||
|
// Else zero bit for short pulse.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Useful debug info:
|
||||||
|
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
|
||||||
|
|
||||||
|
// Verify checksum of received data.
|
||||||
|
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
|
||||||
|
if (type == DHT11) {
|
||||||
|
// Get humidity and temp for DHT11 sensor.
|
||||||
|
*humidity = (float)data[0];
|
||||||
|
*temperature = (float)data[2];
|
||||||
|
}
|
||||||
|
else if (type == DHT22) {
|
||||||
|
// Calculate humidity and temp for DHT22 sensor.
|
||||||
|
*humidity = (data[0] * 256 + data[1]) / 10.0f;
|
||||||
|
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
|
||||||
|
if (data[2] & 0x80) {
|
||||||
|
*temperature *= -1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DHT_SUCCESS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return DHT_ERROR_CHECKSUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/c/adafruit/Raspberry_Pi_2/pi_2_dht_read.h
Normal file
32
src/main/c/adafruit/Raspberry_Pi_2/pi_2_dht_read.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
#ifndef PI_2_DHT_READ_H
|
||||||
|
#define PI_2_DHT_READ_H
|
||||||
|
|
||||||
|
#include "../common_dht_read.h"
|
||||||
|
|
||||||
|
// Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be
|
||||||
|
// returned in the provided parameters. If a successfull reading could be made a value of 0
|
||||||
|
// (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will
|
||||||
|
// be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
|
||||||
|
int pi_2_dht_read(int sensor, int pin, float* humidity, float* temperature);
|
||||||
|
|
||||||
|
#endif
|
||||||
71
src/main/c/adafruit/Raspberry_Pi_2/pi_2_mmio.c
Normal file
71
src/main/c/adafruit/Raspberry_Pi_2/pi_2_mmio.c
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pi_2_mmio.h"
|
||||||
|
|
||||||
|
#define GPIO_BASE_OFFSET 0x200000
|
||||||
|
#define GPIO_LENGTH 4096
|
||||||
|
|
||||||
|
volatile uint32_t* pi_2_mmio_gpio = NULL;
|
||||||
|
|
||||||
|
int pi_2_mmio_init(void) {
|
||||||
|
if (pi_2_mmio_gpio == NULL) {
|
||||||
|
// Check for GPIO and peripheral addresses from device tree.
|
||||||
|
// Adapted from code in the RPi.GPIO library at:
|
||||||
|
// http://sourceforge.net/p/raspberry-gpio-python/
|
||||||
|
FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
|
||||||
|
if (fp == NULL) {
|
||||||
|
return MMIO_ERROR_OFFSET;
|
||||||
|
}
|
||||||
|
fseek(fp, 4, SEEK_SET);
|
||||||
|
unsigned char buf[4];
|
||||||
|
if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) {
|
||||||
|
return MMIO_ERROR_OFFSET;
|
||||||
|
}
|
||||||
|
uint32_t peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
|
||||||
|
uint32_t gpio_base = peri_base + GPIO_BASE_OFFSET;
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
int fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
|
||||||
|
if (fd == -1) {
|
||||||
|
// Error opening /dev/gpiomem.
|
||||||
|
return MMIO_ERROR_DEVMEM;
|
||||||
|
}
|
||||||
|
// Map GPIO memory to location in process space.
|
||||||
|
pi_2_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gpio_base);
|
||||||
|
close(fd);
|
||||||
|
if (pi_2_mmio_gpio == MAP_FAILED) {
|
||||||
|
// Don't save the result if the memory mapping failed.
|
||||||
|
pi_2_mmio_gpio = NULL;
|
||||||
|
return MMIO_ERROR_MMAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MMIO_SUCCESS;
|
||||||
|
}
|
||||||
62
src/main/c/adafruit/Raspberry_Pi_2/pi_2_mmio.h
Normal file
62
src/main/c/adafruit/Raspberry_Pi_2/pi_2_mmio.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
// Simple fast memory-mapped GPIO library for the Raspberry Pi.
|
||||||
|
#ifndef PI_2_MMIO_H
|
||||||
|
#define PI_2_MMIO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MMIO_SUCCESS 0
|
||||||
|
#define MMIO_ERROR_DEVMEM -1
|
||||||
|
#define MMIO_ERROR_MMAP -2
|
||||||
|
#define MMIO_ERROR_OFFSET -3
|
||||||
|
|
||||||
|
extern volatile uint32_t* pi_2_mmio_gpio;
|
||||||
|
|
||||||
|
int pi_2_mmio_init(void);
|
||||||
|
|
||||||
|
static inline void pi_2_mmio_set_input(const int gpio_number) {
|
||||||
|
// Set GPIO register to 000 for specified GPIO number.
|
||||||
|
*(pi_2_mmio_gpio+((gpio_number)/10)) &= ~(7<<(((gpio_number)%10)*3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pi_2_mmio_set_output(const int gpio_number) {
|
||||||
|
// First set to 000 using input function.
|
||||||
|
pi_2_mmio_set_input(gpio_number);
|
||||||
|
// Next set bit 0 to 1 to set output.
|
||||||
|
*(pi_2_mmio_gpio+((gpio_number)/10)) |= (1<<(((gpio_number)%10)*3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pi_2_mmio_set_high(const int gpio_number) {
|
||||||
|
*(pi_2_mmio_gpio+7) = 1 << gpio_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pi_2_mmio_set_low(const int gpio_number) {
|
||||||
|
*(pi_2_mmio_gpio+10) = 1 << gpio_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t pi_2_mmio_input(const int gpio_number) {
|
||||||
|
return *(pi_2_mmio_gpio+13) & (1 << gpio_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
66
src/main/c/adafruit/common_dht_read.c
Normal file
66
src/main/c/adafruit/common_dht_read.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "common_dht_read.h"
|
||||||
|
|
||||||
|
void busy_wait_milliseconds(uint32_t millis) {
|
||||||
|
// Set delay time period.
|
||||||
|
struct timeval deltatime;
|
||||||
|
deltatime.tv_sec = millis / 1000;
|
||||||
|
deltatime.tv_usec = (millis % 1000) * 1000;
|
||||||
|
struct timeval walltime;
|
||||||
|
// Get current time and add delay to find end time.
|
||||||
|
gettimeofday(&walltime, NULL);
|
||||||
|
struct timeval endtime;
|
||||||
|
timeradd(&walltime, &deltatime, &endtime);
|
||||||
|
// Tight loop to waste time (and CPU) until enough time as elapsed.
|
||||||
|
while (timercmp(&walltime, &endtime, <)) {
|
||||||
|
gettimeofday(&walltime, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep_milliseconds(uint32_t millis) {
|
||||||
|
struct timespec sleep;
|
||||||
|
sleep.tv_sec = millis / 1000;
|
||||||
|
sleep.tv_nsec = (millis % 1000) * 1000000L;
|
||||||
|
while (clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_max_priority(void) {
|
||||||
|
struct sched_param sched;
|
||||||
|
memset(&sched, 0, sizeof(sched));
|
||||||
|
// Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
|
||||||
|
sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||||
|
sched_setscheduler(0, SCHED_FIFO, &sched);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_default_priority(void) {
|
||||||
|
struct sched_param sched;
|
||||||
|
memset(&sched, 0, sizeof(sched));
|
||||||
|
// Go back to default scheduler with default 0 priority.
|
||||||
|
sched.sched_priority = 0;
|
||||||
|
sched_setscheduler(0, SCHED_OTHER, &sched);
|
||||||
|
}
|
||||||
51
src/main/c/adafruit/common_dht_read.h
Normal file
51
src/main/c/adafruit/common_dht_read.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2014 Adafruit Industries
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
#ifndef COMMON_DHT_READ_H
|
||||||
|
#define COMMON_DHT_READ_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Define errors and return values.
|
||||||
|
#define DHT_ERROR_TIMEOUT -1
|
||||||
|
#define DHT_ERROR_CHECKSUM -2
|
||||||
|
#define DHT_ERROR_ARGUMENT -3
|
||||||
|
#define DHT_ERROR_GPIO -4
|
||||||
|
#define DHT_SUCCESS 0
|
||||||
|
|
||||||
|
// Define sensor types.
|
||||||
|
#define DHT11 11
|
||||||
|
#define DHT22 22
|
||||||
|
#define AM2302 22
|
||||||
|
|
||||||
|
// Busy wait delay for most accurate timing, but high CPU usage.
|
||||||
|
// Only use this for short periods of time (a few hundred milliseconds at most)!
|
||||||
|
void busy_wait_milliseconds(uint32_t millis);
|
||||||
|
|
||||||
|
// General delay that sleeps so CPU usage is low, but accuracy is potentially bad.
|
||||||
|
void sleep_milliseconds(uint32_t millis);
|
||||||
|
|
||||||
|
// Increase scheduling priority and algorithm to try to get 'real time' results.
|
||||||
|
void set_max_priority(void);
|
||||||
|
|
||||||
|
// Drop scheduling priority back to normal/default.
|
||||||
|
void set_default_priority(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
4
src/main/c/compile.sh
Executable file
4
src/main/c/compile.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
rm testAdafruit;
|
||||||
|
gcc -Wall -I. -Iadafruit/Raspberry_Pi_2 adafruit/common_dht_read.c adafruit/Raspberry_Pi_2/pi_2_mmio.c adafruit/Raspberry_Pi_2/pi_2_dht_read.c testAdafruit.c -o testAdafruit
|
||||||
30
src/main/c/testAdafruit.c
Normal file
30
src/main/c/testAdafruit.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "adafruit/Raspberry_Pi_2/pi_2_dht_read.h"
|
||||||
|
|
||||||
|
int main( void )
|
||||||
|
{
|
||||||
|
printf( "Raspberry Pi 2 DHT11 test program\n" );
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int res;
|
||||||
|
float humidity = 0, temperature = 0;
|
||||||
|
int sensor = 11;
|
||||||
|
int pin = 4;
|
||||||
|
for (i = 1; i < 15; ++i){
|
||||||
|
res = pi_2_dht_read(sensor, pin, &humidity, &temperature);
|
||||||
|
if(res == 0){
|
||||||
|
printf("Temperature : %f\n", temperature);
|
||||||
|
printf("Humidity : %f\n", humidity);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
printf("Error when reading from sensor : %d\n", res);
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
src/main/java/nl/lengrand/therobottle/GreetApplication.java
Normal file
38
src/main/java/nl/lengrand/therobottle/GreetApplication.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
|
import javax.ws.rs.ApplicationPath;
|
||||||
|
import javax.ws.rs.core.Application;
|
||||||
|
|
||||||
|
import io.helidon.common.CollectionsHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Application that produces a greeting message.
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
@ApplicationPath("/")
|
||||||
|
public class GreetApplication extends Application {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Class<?>> getClasses() {
|
||||||
|
return CollectionsHelper.setOf(GreetResource.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
130
src/main/java/nl/lengrand/therobottle/GreetResource.java
Normal file
130
src/main/java/nl/lengrand/therobottle/GreetResource.java
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonBuilderFactory;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple JAX-RS resource to greet you. Examples:
|
||||||
|
*
|
||||||
|
* Get default greeting message:
|
||||||
|
* curl -X GET http://localhost:8080/greet
|
||||||
|
*
|
||||||
|
* Get greeting message for Joe:
|
||||||
|
* curl -X GET http://localhost:8080/greet/Joe
|
||||||
|
*
|
||||||
|
* Change greeting
|
||||||
|
* curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting
|
||||||
|
*
|
||||||
|
* The message is returned as a JSON object.
|
||||||
|
*/
|
||||||
|
@Path("/greet")
|
||||||
|
@RequestScoped
|
||||||
|
public class GreetResource {
|
||||||
|
|
||||||
|
private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The greeting message provider.
|
||||||
|
*/
|
||||||
|
private final GreetingProvider greetingProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using constructor injection to get a configuration property.
|
||||||
|
* By default this gets the value from META-INF/microprofile-config
|
||||||
|
*
|
||||||
|
* @param greetingConfig the configured greeting message
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
public GreetResource(GreetingProvider greetingConfig) {
|
||||||
|
this.greetingProvider = greetingConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a wordly greeting message.
|
||||||
|
*
|
||||||
|
* @return {@link JsonObject}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:designforextension")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public JsonObject getDefaultMessage() {
|
||||||
|
return createResponse("World");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a greeting message using the name that was provided.
|
||||||
|
*
|
||||||
|
* @param name the name to greet
|
||||||
|
* @return {@link JsonObject}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:designforextension")
|
||||||
|
@Path("/{name}")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public JsonObject getMessage(@PathParam("name") String name) {
|
||||||
|
return createResponse(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the greeting to use in future messages.
|
||||||
|
*
|
||||||
|
* @param jsonObject JSON containing the new greeting
|
||||||
|
* @return {@link Response}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:designforextension")
|
||||||
|
@Path("/greeting")
|
||||||
|
@PUT
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Response updateGreeting(JsonObject jsonObject) {
|
||||||
|
|
||||||
|
if (!jsonObject.containsKey("greeting")) {
|
||||||
|
JsonObject entity = JSON.createObjectBuilder()
|
||||||
|
.add("error", "No greeting provided")
|
||||||
|
.build();
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
String newGreeting = jsonObject.getString("greeting");
|
||||||
|
|
||||||
|
greetingProvider.setMessage(newGreeting);
|
||||||
|
return Response.status(Response.Status.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject createResponse(String who) {
|
||||||
|
String msg = String.format("%s %s!", greetingProvider.getMessage(), who);
|
||||||
|
|
||||||
|
return JSON.createObjectBuilder()
|
||||||
|
.add("message", msg)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/nl/lengrand/therobottle/GreetingProvider.java
Normal file
49
src/main/java/nl/lengrand/therobottle/GreetingProvider.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for greeting message.
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
public class GreetingProvider {
|
||||||
|
private final AtomicReference<String> message = new AtomicReference<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new greeting provider, reading the message from configuration.
|
||||||
|
*
|
||||||
|
* @param message greeting to use
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) {
|
||||||
|
this.message.set(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getMessage() {
|
||||||
|
return message.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMessage(String message) {
|
||||||
|
this.message.set(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/nl/lengrand/therobottle/Main.java
Normal file
69
src/main/java/nl/lengrand/therobottle/Main.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.logging.LogManager;
|
||||||
|
|
||||||
|
import io.helidon.microprofile.server.Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application main class.
|
||||||
|
*/
|
||||||
|
public final class Main {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cannot be instantiated.
|
||||||
|
*/
|
||||||
|
private Main() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application main entry point.
|
||||||
|
* @param args command line arguments
|
||||||
|
* @throws IOException if there are problems reading logging properties
|
||||||
|
*/
|
||||||
|
public static void main(final String[] args) throws IOException {
|
||||||
|
// load logging configuration
|
||||||
|
setupLogging();
|
||||||
|
|
||||||
|
// start the server
|
||||||
|
Server server = startServer();
|
||||||
|
|
||||||
|
System.out.println("http://localhost:" + server.port() + "/greet");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server.
|
||||||
|
* @return the created {@link Server} instance
|
||||||
|
*/
|
||||||
|
static Server startServer() {
|
||||||
|
// Server will automatically pick up configuration from
|
||||||
|
// microprofile-config.properties
|
||||||
|
// and Application classes annotated as @ApplicationScoped
|
||||||
|
return Server.create().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure logging from logging.properties file.
|
||||||
|
*/
|
||||||
|
private static void setupLogging() throws IOException {
|
||||||
|
try (InputStream is = Main.class.getResourceAsStream("/logging.properties")) {
|
||||||
|
LogManager.getLogManager().readConfiguration(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/main/java/nl/lengrand/therobottle/ReactiveService.java
Normal file
39
src/main/java/nl/lengrand/therobottle/ReactiveService.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import io.helidon.microprofile.server.RoutingPath;
|
||||||
|
import io.helidon.security.SecurityContext;
|
||||||
|
import io.helidon.webserver.Routing;
|
||||||
|
import io.helidon.webserver.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO javadoc.
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
@RoutingPath("/reactive")
|
||||||
|
public class ReactiveService implements Service {
|
||||||
|
@Inject
|
||||||
|
private SecurityContext securityContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Routing.Rules rules) {
|
||||||
|
rules.get("/", (req, res) -> res.send("Context: " + securityContext));
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/main/java/nl/lengrand/therobottle/Robottle.java
Normal file
27
src/main/java/nl/lengrand/therobottle/Robottle.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
public class Robottle {
|
||||||
|
|
||||||
|
// public static void main(String[] args) throws InterruptedException, ExecutionException {
|
||||||
|
// Dht11Driver theDriver = new Dht11Driver();
|
||||||
|
// theDriver.sayHello();
|
||||||
|
//
|
||||||
|
// FaunaApi api = new FaunaApi();
|
||||||
|
// Thread.sleep(1000);
|
||||||
|
//
|
||||||
|
//// Let's see if it runs until tomorrow!
|
||||||
|
// while(true){
|
||||||
|
// float [] res = theDriver.getTemperatureAndHumidity();
|
||||||
|
// if(res[0] != 0 && res[1] != 0){
|
||||||
|
// System.out.println("Sending " + res[0] + " " + res[1]);
|
||||||
|
// api.add(res);
|
||||||
|
// api.update(res);
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// System.out.println("Incorrect data!" + res[0] + " " + res[1]);
|
||||||
|
// }
|
||||||
|
// Thread.sleep(10000);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package nl.lengrand.therobottle.driver;
|
||||||
|
|
||||||
|
public class Dht11Driver {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary("dht11");
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void sayHello();
|
||||||
|
|
||||||
|
public native float[] getTemperatureAndHumidity();
|
||||||
|
}
|
||||||
65
src/main/java/nl/lengrand/therobottle/fauna/Connection.java
Normal file
65
src/main/java/nl/lengrand/therobottle/fauna/Connection.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package nl.lengrand.therobottle.fauna;
|
||||||
|
|
||||||
|
import com.faunadb.client.FaunaClient;
|
||||||
|
import com.faunadb.client.query.Language;
|
||||||
|
import com.faunadb.client.types.Value;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static com.faunadb.client.query.Language.*;
|
||||||
|
|
||||||
|
public class Connection {
|
||||||
|
|
||||||
|
public static final String API_KEY_NAME = "ROBOTTLE_KEY";
|
||||||
|
public final static String DB_NAME = "robottle";
|
||||||
|
public final static String COLLECTION_NAME = "sensors";
|
||||||
|
public final static String UPDATE_DEVICE_NAME = "robottle_00";
|
||||||
|
public final static String INDEX_NAME = "sensor_data";
|
||||||
|
public final static String INDEX_ALL_NAME = "all_sensors";
|
||||||
|
|
||||||
|
private FaunaClient client;
|
||||||
|
|
||||||
|
public Connection(){
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInit(){
|
||||||
|
return client != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(){
|
||||||
|
try {
|
||||||
|
this.client = createConnection();
|
||||||
|
} catch (ExecutionException | InterruptedException | ConnectionException e) {
|
||||||
|
System.out.println("Problem while initializing connection with FaunaDb");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getKey() {
|
||||||
|
return System.getenv(API_KEY_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDbKey(FaunaClient adminClient) throws InterruptedException, ExecutionException {
|
||||||
|
Value keyResults = adminClient.query(
|
||||||
|
CreateKey(Obj("database", Database(Language.Value(DB_NAME)), "role", Language.Value("server")))
|
||||||
|
).get();
|
||||||
|
|
||||||
|
return keyResults.at("secret").to(String.class).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FaunaClient createConnection() throws ExecutionException, InterruptedException, ConnectionException {
|
||||||
|
FaunaClient adminClient = this.createAdminConnection();
|
||||||
|
return adminClient.newSessionClient(getDbKey(adminClient));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FaunaClient createAdminConnection() throws ConnectionException {
|
||||||
|
if(getKey() == null) throw new ConnectionException("Local API key not found " + API_KEY_NAME );
|
||||||
|
return FaunaClient.builder()
|
||||||
|
.withSecret(getKey())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FaunaClient getClient(){
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package nl.lengrand.therobottle.fauna;
|
||||||
|
|
||||||
|
public class ConnectionException extends Exception {
|
||||||
|
public ConnectionException(String errorMessage) {
|
||||||
|
super(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main/java/nl/lengrand/therobottle/fauna/FaunaApi.java
Normal file
47
src/main/java/nl/lengrand/therobottle/fauna/FaunaApi.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package nl.lengrand.therobottle.fauna;
|
||||||
|
|
||||||
|
import com.faunadb.client.query.Language;
|
||||||
|
import com.faunadb.client.types.Value;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static com.faunadb.client.query.Language.*;
|
||||||
|
import static fauna.Connection.*;
|
||||||
|
|
||||||
|
public class FaunaApi {
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
public FaunaApi(){
|
||||||
|
this.connection = new Connection();
|
||||||
|
connection.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(float[] res) throws ExecutionException, InterruptedException {
|
||||||
|
Value addDataResult = connection.getClient().query(
|
||||||
|
Create(
|
||||||
|
Collection(Language.Value(COLLECTION_NAME)),
|
||||||
|
Obj("data",
|
||||||
|
Obj( "temperature", Language.Value(res[0]), "humidity", Language.Value(res[1]) )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Added sensor data to collection " + COLLECTION_NAME + ":\n " + addDataResult + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(float[] res) throws ExecutionException, InterruptedException {
|
||||||
|
Value updateDataResult =
|
||||||
|
connection.getClient().query(
|
||||||
|
Update(
|
||||||
|
Select(Language.Value("ref"), Get(Match(Index(INDEX_NAME), Language.Value(UPDATE_DEVICE_NAME)))),
|
||||||
|
Obj("data",
|
||||||
|
Obj(
|
||||||
|
"temperature", Language.Value(res[0]),
|
||||||
|
"humidity", Language.Value(res[1])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Updated sensor data from collection " + COLLECTION_NAME + ":\n " + updateDataResult + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package nl.lengrand.therobottle.fauna.setup;
|
||||||
|
|
||||||
|
import com.faunadb.client.FaunaClient;
|
||||||
|
import com.faunadb.client.types.Value;
|
||||||
|
import fauna.Connection;
|
||||||
|
import fauna.ConnectionException;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static com.faunadb.client.query.Language.*;
|
||||||
|
import static fauna.Connection.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to create the database and indexes. Should be run only once!
|
||||||
|
*/
|
||||||
|
public class FaunaDbSetup {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws ExecutionException, InterruptedException, ConnectionException {
|
||||||
|
System.out.println("Setting up Database " + DB_NAME);
|
||||||
|
|
||||||
|
Connection connection = new Connection();
|
||||||
|
|
||||||
|
FaunaClient adminClient = connection.createAdminConnection();
|
||||||
|
|
||||||
|
createDatabase(adminClient);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
FaunaClient dbClient = connection.createConnection();
|
||||||
|
|
||||||
|
createCollection(dbClient);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
createIndex(dbClient);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
createAllIndex(dbClient);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
createInitialValue(dbClient);
|
||||||
|
|
||||||
|
adminClient.close();
|
||||||
|
System.out.println("Client closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getDbKey(FaunaClient adminClient) throws InterruptedException, ExecutionException {
|
||||||
|
Value keyResults = adminClient.query(
|
||||||
|
CreateKey(Obj("database", Database(Language.Value(DB_NAME)), "role", Language.Value("server")))
|
||||||
|
).get();
|
||||||
|
|
||||||
|
return keyResults.at("secret").to(String.class).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createIndex(FaunaClient dbClient) throws InterruptedException, ExecutionException {
|
||||||
|
Value indexResults = dbClient.query(
|
||||||
|
CreateIndex(
|
||||||
|
Obj("name", Language.Value(INDEX_NAME),
|
||||||
|
"source", Collection(Language.Value(COLLECTION_NAME)),
|
||||||
|
"unique", Language.Value(true),
|
||||||
|
"terms", Arr(Obj("field", Arr(Language.Value("data"), Language.Value("name"))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Create name index for " + DB_NAME + ":\n " + indexResults + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createAllIndex(FaunaClient dbClient) throws InterruptedException, ExecutionException {
|
||||||
|
Value indexResults = dbClient.query(
|
||||||
|
CreateIndex(
|
||||||
|
Obj("name", Language.Value(INDEX_ALL_NAME),
|
||||||
|
"source", Collection(Language.Value(COLLECTION_NAME))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Create all index for " + DB_NAME + ":\n " + indexResults + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void createCollection(FaunaClient dbClient) throws InterruptedException, ExecutionException {
|
||||||
|
Value collectionResults = dbClient.query(
|
||||||
|
CreateCollection(
|
||||||
|
Obj("name", Language.Value(COLLECTION_NAME), "history_days", null)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Create Collection for " + DB_NAME + ":\n " + collectionResults + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createDatabase(FaunaClient adminClient) {
|
||||||
|
adminClient.query(
|
||||||
|
CreateDatabase(
|
||||||
|
Obj("name", Language.Value(DB_NAME))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println("Db created");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createInitialValue(FaunaClient client) throws ExecutionException, InterruptedException {
|
||||||
|
Value init = client.query(
|
||||||
|
Create(
|
||||||
|
Collection(Language.Value(COLLECTION_NAME)),
|
||||||
|
Obj("data",
|
||||||
|
Obj("name", Language.Value(UPDATE_DEVICE_NAME))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
System.out.println("Added initial item to collection " + COLLECTION_NAME + ":\n " + init + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/main/java/nl/lengrand/therobottle/package-info.java
Normal file
20
src/main/java/nl/lengrand/therobottle/package-info.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quickstart MicroProfile example.
|
||||||
|
*/
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
26
src/main/resources/META-INF/beans.xml
Normal file
26
src/main/resources/META-INF/beans.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||||
|
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
|
||||||
|
version="2.0"
|
||||||
|
bean-discovery-mode="annotated">
|
||||||
|
</beans>
|
||||||
22
src/main/resources/META-INF/microprofile-config.properties
Normal file
22
src/main/resources/META-INF/microprofile-config.properties
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Application properties. This is the default greeting
|
||||||
|
app.greeting=Hello
|
||||||
|
|
||||||
|
# Microprofile server properties
|
||||||
|
server.port=8080
|
||||||
|
server.host=0.0.0.0
|
||||||
37
src/main/resources/logging.properties
Normal file
37
src/main/resources/logging.properties
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Example Logging Configuration File
|
||||||
|
# For more information see $JAVA_HOME/jre/lib/logging.properties
|
||||||
|
|
||||||
|
# Send messages to the console
|
||||||
|
handlers=io.helidon.common.HelidonConsoleHandler
|
||||||
|
|
||||||
|
# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
|
||||||
|
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
|
||||||
|
|
||||||
|
# Global logging level. Can be overridden by specific loggers
|
||||||
|
.level=INFO
|
||||||
|
|
||||||
|
# Component specific log levels
|
||||||
|
#io.helidon.webserver.level=INFO
|
||||||
|
#io.helidon.config.level=INFO
|
||||||
|
#io.helidon.security.level=INFO
|
||||||
|
#io.helidon.microprofile.level=INFO
|
||||||
|
#io.helidon.common.level=INFO
|
||||||
|
#io.netty.level=INFO
|
||||||
|
#org.glassfish.jersey.level=INFO
|
||||||
|
#org.jboss.weld=INFO
|
||||||
96
src/test/java/nl/lengrand/therobottle/MainTest.java
Normal file
96
src/test/java/nl/lengrand/therobottle/MainTest.java
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package nl.lengrand.therobottle;
|
||||||
|
|
||||||
|
import javax.enterprise.inject.se.SeContainer;
|
||||||
|
import javax.enterprise.inject.spi.CDI;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.ws.rs.client.Client;
|
||||||
|
import javax.ws.rs.client.ClientBuilder;
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import io.helidon.microprofile.server.Server;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class MainTest {
|
||||||
|
private static Server server;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void startTheServer() throws Exception {
|
||||||
|
server = Main.startServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHelloWorld() {
|
||||||
|
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
|
||||||
|
JsonObject jsonObject = client
|
||||||
|
.target(getConnectionString("/greet"))
|
||||||
|
.request()
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assertions.assertEquals("Hello World!", jsonObject.getString("message"),
|
||||||
|
"default message");
|
||||||
|
|
||||||
|
jsonObject = client
|
||||||
|
.target(getConnectionString("/greet/Joe"))
|
||||||
|
.request()
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assertions.assertEquals("Hello Joe!", jsonObject.getString("message"),
|
||||||
|
"hello Joe message");
|
||||||
|
|
||||||
|
Response r = client
|
||||||
|
.target(getConnectionString("/greet/greeting"))
|
||||||
|
.request()
|
||||||
|
.put(Entity.entity("{\"greeting\" : \"Hola\"}", MediaType.APPLICATION_JSON));
|
||||||
|
Assertions.assertEquals(204, r.getStatus(), "PUT status code");
|
||||||
|
|
||||||
|
jsonObject = client
|
||||||
|
.target(getConnectionString("/greet/Jose"))
|
||||||
|
.request()
|
||||||
|
.get(JsonObject.class);
|
||||||
|
Assertions.assertEquals("Hola Jose!", jsonObject.getString("message"),
|
||||||
|
"hola Jose message");
|
||||||
|
|
||||||
|
r = client
|
||||||
|
.target(getConnectionString("/metrics"))
|
||||||
|
.request()
|
||||||
|
.get();
|
||||||
|
Assertions.assertEquals(200, r.getStatus(), "GET metrics status code");
|
||||||
|
|
||||||
|
r = client
|
||||||
|
.target(getConnectionString("/health"))
|
||||||
|
.request()
|
||||||
|
.get();
|
||||||
|
Assertions.assertEquals(200, r.getStatus(), "GET health status code");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void destroyClass() {
|
||||||
|
CDI<Object> current = CDI.current();
|
||||||
|
((SeContainer) current).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConnectionString(String path) {
|
||||||
|
return "http://localhost:" + server.port() + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/test/resources/META-INF/microprofile-config.properties
Normal file
22
src/test/resources/META-INF/microprofile-config.properties
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Override configuration to use a random port for the unit tests
|
||||||
|
config_ordinal=1000
|
||||||
|
# Microprofile server properties
|
||||||
|
server.port=-1
|
||||||
|
server.host=0.0.0.0
|
||||||
Reference in New Issue
Block a user