You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
Blaine Motsinger bf7cbb451f Convert README.txt to markdown 1 year ago
config removed default api key pass from config 5 years ago
systemd added systemd file 5 years ago
.gitignore refined logic to read the pin and error 5 years ago
README.md Convert README.txt to markdown 1 year ago
package.json corrected node-dht-sensor version 5 years ago
weather-api.js removed default api key pass from config 5 years ago

README.md

NAME

weather-api - simple API in nodejs

DESCRIPTION

This project provides a simple API, written in nodejs, which serves temperature and humidity data from the Raspberry Pi.

Supported sensors are the DHT11 or DHT22 (AM2302) read using the bcm2835 C library.

SYNOPSIS

server ~/weather-api $ nodejs weather-api.js 
[06152018-233738] [info] weather-api - version 0.1.11
[06152018-233738] [info] environment: development
[06152018-233738] [info] serving: 0.0.0.0:3000
[06152018-233948] 10.0.0.103 GET /weather 200

laptop ~ $ curl -X GET -H 'API_KEY: 1234567890qwerty' server:3000/weather
{
   "temperature" : 85,
   "humidity" : 65
}

ENDPOINTS

The API is served over port 3000 and bound to all addresses by default, but can be configured to a specific address or port (see the 'CONFIGURATION' section below).

/weather

METHODS

GET

This API is a read-only resource; GET is the only allowed method.

All other methods requested to the API will return exceptions (see the 'RESPONSES' section below).

PARAMETERS

The parameters to the /weather endpoint define what resource you want to read.

temperature

Provides the temperature reading in F.

http://server:3000/weather/temperature

{
   "temperature" : 85
}

humidity

Provides the relative humidity reading in percent.

http://server:3000/weather/humidity

{
   "humidity" : 65
}

RETURNS

A JSON datastructure containing key value pairs.

{
   "temperature" : 85,
   "humidity" : 65
}

[temperature|humidity]

The value read from the requested resource.

RESPONSES

The following are the responses the API may return.

401 (Unauthorized)

The API_KEY header was not found, or the key didn't match.

The exception string, 'unauthorized', with the 401 response code, is returned.

# request without the API_KEY header
$ curl -sD - -X GET server:3000/weather/temperature
HTTP/1.1 401 Unauthorized
Content-Type: text/plain
Date: Tue, 19 Jun 2018 18:51:43 GMT
Connection: keep-alive
Transfer-Encoding: chunked

unauthorized

405 (Method not allowed)

The method requested was something other than GET.

The exception string, 'METHOD is not allowed', with the 405 response code, is returned. Additionally, the Allow header is set indicating only GET.

# request method other than GET
$ curl -sD - -X POST -H 'API_KEY: 1234567890qwerty' server:3000/weather/temperature
HTTP/1.1 405 Method Not Allowed
Allow: GET
Content-Type: text/plain
Date: Tue, 19 Jun 2018 18:54:18 GMT
Connection: keep-alive
Transfer-Encoding: chunked

POST is not allowed

404 (Not Found)

The requested route was not known.

The exception string, 'URL is not a known route', with the 404 response code, is returned.

# request an unknown route
$ curl -sD - -X GET -H 'API_KEY: 1234567890qwerty' server:3000/paper
HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Tue, 19 Jun 2018 19:12:14 GMT
Connection: keep-alive
Transfer-Encoding: chunked

/paper is not a known route

# unknown parameter to a known route
$ curl -sD - -X GET -H 'API_KEY: 1234567890qwerty' server:3000/weather/forecast
HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Tue, 19 Jun 2018 19:10:17 GMT
Connection: keep-alive
Transfer-Encoding: chunked

/weather/forecast is not a known route

# extra parameters to a known route and known parameter
$ curl -sD - -X GET -H 'API_KEY: 1234567890qwerty' server:3000/weather/temperature?test=1
HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Tue, 19 Jun 2018 19:13:33 GMT
Connection: keep-alive
Transfer-Encoding: chunked

/weather/temperature?test=1 is not a known route

500 (Internal Server Error)

There was an issue while reading the sensor.

The exception string, 'unknown error', with the 500 response code, is returned.

$ curl -s -D - -X GET -H 'API_KEY: 1234567890qwerty' server:3000/weather/temperature
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain
Date: Tue, 17 Jun 2018 00:00:18 GMT
Connection: keep-alive
Transfer-Encoding: chunked

unknown error

200 (OK)

Everything in the request was good and there were no issues on the backend.

The JSON data structure, with requested resource and 200 response code, is returned.

# request meeting all criteria
$ curl -sD - -X GET -H 'API_KEY: 1234567890qwerty' server:3000/weather
HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 19 Jun 2018 19:17:19 GMT
Connection: keep-alive
Transfer-Encoding: chunked

{"temperature":85,"humidity":65}

LOGGING

The API outputs timestamped startup info to stdout, as well as request, response, and error details.

[06162018-002138] [info] weather-api server started - verison 0.1.11
[06162018-002138] [info] environment: development
[06162018-002138] [info] serving: 0.0.0.0:3000
[06162018-002156] 10.0.0.103 GET /weather/humidity 401
[06162018-002218] 10.0.0.103 GET /weather/humidity 200
[06162018-002851] 10.0.0.103 GET /weather/notaresource 404
[06162018-003000] 10.0.0.103 POST /weather/temperature 405
[06172018-000018] 10.0.0.103 GET /weather/temperature 500
[06172018-000020] [error] Error: failed to read sensor

CONFIGURATION

The API requires configuration settings which are stored and defined within the ./config/application.js file located within the project's base dir. The config object is exported and accessed within weather-api.js.

# ./config/application.js
config.address     = '0.0.0.0';
config.port        = 3000;
config.api_key     = '1234567890qwerty';
config.environment = 'development';
config.dht         = 22;
config.pin         = 4;

The key value pairs within the configuration are verified on startup. The server will fail to start if any of the names or values aren't correct or within range. If there is a failure, the reason will be logged.

# unexpected key name in the config
[06292018-025505] [info] weather-api - version 0.1.11
[06292018-025505] [error] config verification failed
[06292018-025505] [error] config.interfaces: interfaces is not a valid key name
[06292018-025505] [error] exiting

# incorrect value
[06292018-025521] [info] weather-api - version 0.1.11
[06292018-025521] [error] config verification failed
[06292018-025521] [error] config.port: 3000a is not a valid value
[06292018-025521] [error] exiting

config.address

The address on the Raspberry Pi to bind to.

Verification on startup allows for both ip addresses and hostnames.

config.port

The port to listen on.

Verification on startup allows for digits only.

config.api_key

The authorization header string to validate against.

Verification on startup allows for case-insensitive alpha-numeric characters, and requires between a 16 and 40 character length string.

config.environment

Whether the API is running on development or production. If development, values of 'devel' will be returned instead of reading the values via GPIO.

Verification requires either 'development' or 'production' as values.

config.dht

The temperature/humidity sensor being used. Supported config values are:

11

If using the DHT11.

22

If using the DHT22 (or AM2302).

config.pin

The GPIO pin the DHT sensor is connected to.

Verification on startup requires digits only.

INSTALLATION

Before installing the module dependencies for this project, the bcm2835 C library will need to be installed.

First, ensure you have 'build-essential' and 'make' installed so you can compile the library.

# apt-get install build-essential make

Download the bcm2835 library source code to the desired location and extract the tarball. You'll want to ensure you have the latest version before downloading; the link below is for v1.56 which might not be the latest as you're reading this.

# cd /usr/local/src/
/usr/local/src # wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.56.tar.gz
/usr/local/src # tar zxvf bcm2835-1.56.tar.gz

Now, configure, make, test, and install the library.

/usr/local/src # cd bcm2835-1.56/
/usr/local/src/bcm2835-1.56 # ./configure
/usr/local/src/bcm2835-1.56 # make
/usr/local/src/bcm2835-1.56 # make check
/usr/local/src/bcm2835-1.56 # make install

If you receive the following error when running the API through nodejs:

bcm2835_init: Unable to open /dev/gpiomem: Permission denied

You're probably running the API as an un-privileged user which isn't in the gpio group. You will need to add the user to the gpio group so it can access gpiomem (replace apiuser in the example below with the user you're running this software as). The 'pi' user should already be in the gpio group.

# adduser apiuser gpio

Included within the systemd directory is a service file for basic control via systemd. The settings within the service file use generic user and directory settings, and need to be adjusted before enabling and starting the service.

Once you're updated the service file, copy it into /etc/systemd/system/, enable, and start.

# systemctl enable weather-api.service
# systemctl start weather-api.service

After starting you can check the status through systemctl.

# systemctl status weather-api.service
● weather-api.service
   Loaded: loaded (/etc/systemd/system/weather-api.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2018-07-04 01:26:48 UTC; 4s ago
 Main PID: 3243 (node)
   CGroup: /system.slice/weather-api.service
           └─3243 /usr/local/bin/node /home/apiuser/weather-api/weather-api.js

Jul 04 01:26:48 server systemd[1]: Started weather-api.service.
Jul 04 01:26:51 server weather-api[3243]: [07042018-012651] [info] weather-api - version 0.1.11
Jul 04 01:26:51 server weather-api[3243]: [07042018-012651] [info] server started
Jul 04 01:26:51 server weather-api[3243]: [07042018-012651] [info] environment: production
Jul 04 01:26:51 server weather-api[3243]: [07042018-012651] [info] serving: 0.0.0.0:3000

DEPENDENCIES

This project is built using nodejs and utilizes deconstructing assignment from ES6. Because of this, the latest (or newer) nodejs is recommended.

The http library is used but is included through nodejs core. No additional installation is required.

Additionally, the moment and node-dht-sensor libraries are also used. Both are defined in the package.json file within the project's base dir and can be installed via npm.

server ~/weather-api $ npm install

Of note, the node-dht-sensor library requires the bcm2835 C library installed to the Raspberry Pi before installing through npm, else installation will fail. (see the 'INSTALLATION' section above).

AUTHOR

Blaine Motsinger blaine@renderorange.com