Skip to content

Commit

Permalink
first commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
s5uishida committed Aug 18, 2019
1 parent 603738f commit c74e629
Show file tree
Hide file tree
Showing 11 changed files with 435 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
28 changes: 28 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ppd42ns-driver</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
7 changes: 7 additions & 0 deletions .settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
4 changes: 4 additions & 0 deletions .settings/org.eclipse.pde.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
eclipse.preferences.version=1
pluginProject.equinox=false
pluginProject.extensions=false
resolve.requirebundle=false
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2019 Shigeru Ishida

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.
12 changes: 12 additions & 0 deletions META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: java driver for ppd42ns - dust sensor module
Bundle-SymbolicName: ppd42ns-driver
Bundle-Version: 0.1.0
Automatic-Module-Name: ppd42ns-driver
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.pi4j.io.gpio;version="1.2.0",
com.pi4j.io.gpio.event;version="1.2.0",
org.slf4j;version="[1.7.25,1.8.0)"
Export-Package: io.github.s5uishida.iot.device.ppd42ns.driver;version="0.1.0"
Bundle-Vendor: Shigeru Ishida (s5uishida)
99 changes: 98 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,98 @@
# ppd42ns-driver
# ppd42ns-driver
ppd42ns-driver is a java library that operates dust sensor called [PPD42NS](http://wiki.seeedstudio.com/Grove-Dust_Sensor/) to connect PPD42NS to GPIO terminal of Raspberry Pi 3B and make it for use in java.
I releases this in the form of the Eclipse plug-in project.
You need Java 8 or higher.

I use [Pi4J](http://wiki.seeedstudio.com/Grove-Dust_Sensor/)
for gpio communication in java and have confirmed that it works in Raspberry Pi 3B ([Raspbian Buster Lite OS](https://www.raspberrypi.org/downloads/raspbian/) (2019-07-10)).

## Connection of PPD42NS and Raspberry Pi 3B
**Connect with `Vin <--> Vin`,`GND <--> GND`, `PM2.5 <--> Tx`.**
[This](https://github.com/mauricecyril/pidustsensor) is also helpful.
- `Pins` of [PPD42NS](http://wiki.seeedstudio.com/Grove-Dust_Sensor/)
- Vin (pin#3 - Red)
- GND (pin#1 - Black)
- PM2.5 (pin#4 - Yellow)
- [GPIO of Raspberry Pi 3B](https://www.raspberrypi.org/documentation/usage/gpio/README.md)
- Vin --> (4)
- GND --> (6)
- Tx --> (8) GPIO14

## Install Raspbian Buster Lite OS (2019-07-10)
The reason for using this version is that it is the latest as of July 2019 and [BlueZ](http://www.bluez.org/) 5.50 is included from the beginning, and use Bluetooth and serial communication simultaneously.

## Configuration of Raspbian Buster Lite OS
- Edit `/boot/cmdline.txt`
```
console=serial0,115200 --> removed
```
- Edit `/boot/config.txt`
```
@@ -55,6 +55,10 @@
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
+enable_uart=1
+dtoverlay=pi3-miniuart-bt
+core_freq=250
+
[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-fkms-v3d
```
When editing is complete, reboot.

## Install WiringPi Native Library
Pi4J depends on the [WiringPi](http://wiringpi.com/) native library by Gordon Henderson.
The Pi4J native library is dynamically linked to WiringPi.
```
# apt-get update
# apt-get install wiringpi
```

## Install jdk11 on Raspberry Pi 3B
For example, [jdk11 apt-install](https://apt.bell-sw.com/) at [BELLSOFT](https://bell-sw.com/) is shown below.
```
# wget -q -O - https://download.bell-sw.com/pki/GPG-KEY-bellsoft | apt-key add -
# echo "deb [arch=armhf] https://apt.bell-sw.com/ stable main" | tee /etc/apt/sources.list.d/bellsoft.list
# apt-get update
# apt-get install bellsoft-java11
```

## Install git
If git is not included, please install it.
```
# apt-get install git
```

## Use this with the following bundles
- [SLF4J 1.7.26](https://www.slf4j.org/)
- [Pi4J 1.2 (pi4j-core.jar)](https://pi4j.com/download/pi4j-1.2.zip)

I would like to thank the authors of these very useful codes, and all the contributors.

## How to use
The following sample code will be helpful.
**In the following code, ppd42ns.read() takes about 30 seconds to measure.**
```
import io.github.s5uishida.iot.device.ppd42ns.driver.PPD42NSDriver;
import io.github.s5uishida.iot.device.ppd42ns.driver.PPD42NSObservationData;
public class MyPPD42NS {
private static final Logger LOG = LoggerFactory.getLogger(MyPPD42NS.class);
public static void main(String[] args) {
PPD42NSDriver ppd42ns = PPD42NSDriver.getInstance();
ppd42ns.open();
while (true) {
PPD42NSObservationData data = ppd42ns.read();
LOG.info(data.toString());
}
// if (ppd42ns != null) {
// ppd42ns.close();
// }
}
}
```
Empty file added bin/.gitkeep
Empty file.
5 changes: 5 additions & 0 deletions build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
LICENSE
191 changes: 191 additions & 0 deletions src/io/github/s5uishida/iot/device/ppd42ns/driver/PPD42NSDriver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package io.github.s5uishida.iot.device.ppd42ns.driver;

import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiGpioProvider;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.RaspiPinNumberingScheme;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;

/*
* Refer to http://wiki.seeedstudio.com/Grove-Dust_Sensor/
*
* @author s5uishida
*
*/
public class PPD42NSDriver {
private static final Logger LOG = LoggerFactory.getLogger(PPD42NSDriver.class);

private final Pin GPIO_IN = RaspiPin.GPIO_14;
private final int OBSERVE_TIMEOUT_MILLIS = 30000;
private final int GPIO_IN_TIMEOUT_MILLIS = 50000;

private final GpioController gpio;

private GpioPinDigitalInput diPin;
private String logPrefix;

private final AtomicInteger useCount = new AtomicInteger(0);
private final BlockingQueue<PPD42NSObservationData> queue = new LinkedBlockingQueue<PPD42NSObservationData>();

private static PPD42NSDriver ppd42ns;

private PPD42NSGpioPinListenerDigital ppd42nsListener;

synchronized public static PPD42NSDriver getInstance() {
if (ppd42ns == null) {
ppd42ns = new PPD42NSDriver();
}
return ppd42ns;
}

private PPD42NSDriver() {
GpioFactory.setDefaultProvider(new RaspiGpioProvider(RaspiPinNumberingScheme.BROADCOM_PIN_NUMBERING));
gpio = GpioFactory.getInstance();
logPrefix = "[" + getName() + "] ";
}

synchronized public void open() {
try {
LOG.debug(logPrefix + "before - useCount:{}", useCount.get());
if (useCount.compareAndSet(0, 1)) {
diPin = gpio.provisionDigitalInputPin(GPIO_IN, PinPullResistance.PULL_DOWN);
diPin.setShutdownOptions(true);
ppd42nsListener = new PPD42NSGpioPinListenerDigital(this, queue);
diPin.addListener(ppd42nsListener);
LOG.info(logPrefix + "opened SPI SLCK.");
}
} finally {
LOG.debug(logPrefix + "after - useCount:{}", useCount.get());
}
}

synchronized public void close() {
try {
LOG.debug(logPrefix + "before - useCount:{}", useCount.get());
if (useCount.compareAndSet(1, 0)) {
diPin.removeAllListeners();
gpio.unprovisionPin(diPin);
gpio.shutdown();
LOG.info(logPrefix + "closed SPI SLCK.");
}
} finally {
LOG.debug(logPrefix + "after - useCount:{}", useCount.get());
}
}

public String getName() {
return GPIO_IN.getName().replaceAll("\\s", "_");
}

public String getLogPrefix() {
return logPrefix;
}

public PPD42NSObservationData read() {
queue.clear();
ppd42nsListener.start();
try {
return queue.poll(GPIO_IN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
LOG.warn("caught - {}", e.toString());
return null;
}
}

/******************************************************************************************************************
* Sample main
******************************************************************************************************************/
public static void main(String[] args) {
PPD42NSDriver ppd42ns = PPD42NSDriver.getInstance();
ppd42ns.open();

while (true) {
PPD42NSObservationData data = ppd42ns.read();
LOG.info(data.toString());
}

// if (ppd42ns != null) {
// ppd42ns.close();
// }
}

class PPD42NSGpioPinListenerDigital implements GpioPinListenerDigital {
private final Logger LOG = LoggerFactory.getLogger(PPD42NSGpioPinListenerDigital.class);

private final PPD42NSDriver ppd42ns;
private final BlockingQueue<PPD42NSObservationData> queue;

private Date startTime;
private long startLowTimeMillis;
private long totalLowTimeMillis;

public PPD42NSGpioPinListenerDigital(PPD42NSDriver ppd42ns, BlockingQueue<PPD42NSObservationData> queue) {
this.ppd42ns = ppd42ns;
this.queue = queue;
}

public void reset() {
startTime = null;
startLowTimeMillis = -1;
totalLowTimeMillis = 0;
}

public void start() {
reset();
startTime = new Date();
}

private float pcs2ugm3(float pcs) {
double density = 1.65 * Math.pow(10, 12);
double r25 = 0.44 * Math.pow(10, -6);
double vol25 = (4 / 3) * Math.PI * Math.pow(r25, 3);
double mass25 = density * vol25;
double K = 3531.5;
return (float)(pcs * K * mass25);
}

@Override
public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
LOG.trace(ppd42ns.getLogPrefix() + "{} -> {}", event.getPin(), event.getState());

if (startTime == null) {
return;
}

Date currentTime = new Date();
if (event.getState() == PinState.LOW) {
startLowTimeMillis = currentTime.getTime();
return;
} else if (event.getState() == PinState.HIGH && startLowTimeMillis > 0) {
totalLowTimeMillis += currentTime.getTime() - startLowTimeMillis;
} else {
return;
}

if ((currentTime.getTime() - startTime.getTime()) >= OBSERVE_TIMEOUT_MILLIS) {
float ratio = 100f * ((float)totalLowTimeMillis) / ((float)(currentTime.getTime() - startTime.getTime()));
float pcs = (float)(1.1 * Math.pow(ratio, 3) - 3.8 * Math.pow(ratio, 2) + 520.0 * ratio + 0.62);
float ugm3 = pcs2ugm3(pcs);
PPD42NSObservationData data = new PPD42NSObservationData(startTime, currentTime, pcs, ugm3);
queue.offer(data);
LOG.trace(ppd42ns.getLogPrefix() + "offer - {}", data.toString());
reset();
}
}
}
}
Loading

0 comments on commit c74e629

Please sign in to comment.