Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
daveschumaker committed Aug 28, 2020
0 parents commit e132c57
Show file tree
Hide file tree
Showing 20 changed files with 6,179 additions and 0 deletions.
251 changes: 251 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
module.exports = {
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
jsx: true
},
sourceType: 'module'
},

env: {
browser: true,
node: true,
es6: true
},

globals: {
__DEV__: true,
__PRODUCTION__: true
},

rules: {
// Possible Errors
'comma-dangle': [1, 'never'],
'no-cond-assign': [1, 'always'],
'no-console': 0,
'no-constant-condition': 1,
'no-control-regex': 0,
'no-debugger': 1,
'no-dupe-args': 1,
'no-dupe-keys': 1,
'no-duplicate-case': 0,
'no-empty-character-class': 1,
'no-empty': 1,
'no-ex-assign': 1,
'no-extra-boolean-cast': 1,
'no-extra-parens': 0,
'no-extra-semi': 1,
'no-func-assign': 1,
'no-inner-declarations': 0,
'no-invalid-regexp': 1,
'no-irregular-whitespace': 1,
'no-negated-in-lhs': 1,
'no-obj-calls': 0,
'no-regex-spaces': 1,
'no-sparse-arrays': 1,
'no-unexpected-multiline': 1,
'no-unreachable': 1,
'use-isnan': 1,
'valid-jsdoc': 0,
'valid-typeof': 1,

// Best Practices
'accessor-pairs': 0,
'block-scoped-var': 1,
complexity: 0,
'consistent-return': 0,
curly: ['warn'],
'default-case': 0,
'dot-location': [1, 'property'],
'dot-notation': 1,
eqeqeq: [1, 'smart'],
'guard-for-in': 1,
'no-alert': 1,
'no-caller': 0,
'no-case-declarations ': 0,
'no-div-regex': 1,
'no-else-return': 0,
'no-empty-label': 0,
'no-empty-pattern': 0,
'no-eq-null': 1,
'no-eval': 1,
'no-extend-native': 0,
'no-extra-bind': 1,
'no-fallthrough': 0,
'no-floating-decimal': 1,
'no-implicit-coercion': 1,
'no-implied-eval': 1,
'no-invalid-this': 0,
'no-iterator': 0,
'no-labels': 0,
'no-lone-blocks': 1,
'no-loop-func': 1,
'no-magic-numbers': 0,
'no-multi-spaces': 1,
'no-multi-str': 1,
'no-native-reassign': 1,
'no-new-func': 0,
'no-new-wrappers': 1,
'no-new': 1,
'no-octal-escape': 0,
'no-octal': 0,
'no-param-reassign': 0,
'no-process-env': 0,
'no-proto': 0,
'no-redeclare': 1,
'no-return-assign': 0,
'no-script-url': 0,
'no-self-compare': 1,
'no-sequences': 1,
'no-throw-literal': 0,
'no-unused-expressions': 1,
'no-useless-call': 0,
'no-useless-concat': 1,
'no-void': 0,
'no-warning-comments': 0,
'no-with': 0,
radix: 0,
'vars-on-top': 0,
'wrap-iife': 0,
yoda: 0,

// Strict Mode
strict: 0,

// Variables
'init-declarations': 0,
'no-catch-shadow': 0,
'no-delete-var': 0,
'no-label-var': 1,
'no-shadow-restricted-names': 0,
'no-shadow': 1,
'no-undef-init': 0,
'no-undef': 'error',
'no-undefined': 1,
'no-unused-vars': [
1,
{
varsIgnorePattern: 'StyleSheet'
}
],
'no-use-before-define': 1,

// Node.js and CommonJS
'callback-return': 0,
'global-require': 0,
'handle-callback-err': 0,
'no-mixed-requires': [0],
'no-new-require': 1,
'no-path-concat': 0,
'no-process-exit': 0,
'no-restricted-modules': 0,
'no-sync': 0,

// Stlistic Issues
'array-bracket-spacing': [1, 'never', { objectsInArrays: false }],
'block-spacing': [1, 'always'],
'brace-style': 1,
camelcase: [
1,
{
properties: 'always'
}
],
'comma-spacing': [
1,
{
before: false,
after: true
}
],
'comma-style': [1, 'last'],
'computed-property-spacing': [1, 'never'],
'consistent-this': [1, 'self'],
'eol-last': 0,
'func-names': 0,
'func-style': [0, 'expression'],
'id-length': 0,
'id-match': 0,
indent: 0,
'jsx-quotes': [1, 'prefer-double'],
'key-spacing': [
1,
{
beforeColon: false,
afterColon: true
}
],
'linebreak-style': 0,
'lines-around-comment': 0,
'max-depth': 0,
'max-len': 0,
'max-nested-callbacks': 0,
'max-params': 0,
'max-statements': 0,
'new-cap': 0,
'new-parens': 1,
'newline-after-var': 0,
'no-array-constructor': 0,
'no-bitwise': 0,
'no-continue': 0,
'no-inline-comments': 0,
'no-lonely-if': 0,
'no-mixed-spaces-and-tabs': 1,
'no-multiple-empty-lines': 0,
'no-nested-ternary': 1,
'no-new-object': 1,
'no-plusplus': 0,
'no-restricted-syntax': 0,
'no-spaced-func': 1,
'no-ternary': 0,
'no-trailing-spaces': 1,
'no-underscore-dangle': 0,
'no-unneeded-ternary': 1,
'object-curly-spacing': ['warn', 'always'],
'one-var': 0,
'operator-assignment': 0,
'operator-linebreak': 0,
'padded-blocks': 0,
'quote-props': 0,
quotes: [0, 'single', { allowTemplateLiterals: true }],
'require-jsdoc': 0,
'semi-spacing': [
1,
{
before: false,
after: true
}
],
semi: [1, 'always'],
'sort-vars': 0,
'space-before-blocks': 1,
'space-before-function-paren': 0,
'keyword-spacing': [1, { before: true }],
'space-in-parens': [1, 'never'],
'space-infix-ops': 0,
'space-unary-ops': 0,
'spaced-comment': 0,
'wrap-regex': 0,

// ECMAScript 6
'no-confusing-arrow': 'error',
'arrow-body-style': 0,
'arrow-parens': 0,
'arrow-spacing': 0,
'constructor-super': 0,
'generator-star-spacing': 0,
'no-arrow-condition': 0,
'no-class-assign': 0,
'no-const-assign': 0,
'no-dupe-class-members': 0,
'no-this-before-super': 0,
'no-var': 0,
'object-shorthand': 'warn',
'prefer-arrow-callback': 'warn',
'prefer-const': 0,
'prefer-reflect': 0,
'prefer-spread': 0,
'prefer-template': 0,
'require-yield': 0
}
};
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

config.js
dataStore
dist
node_modules
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Local Air Quality Monitor

![](/media/local-air-screenshot.png?raw=true)

## Introduction

This simple Node app uses the PurpleAir API to display hyper-local air quality information based on PurpleAir IoT sensors located near where you live. You can check check the abundance of sensors near your place by visiting [https://www.purpleair.com/map?mylocation](https://www.purpleair.com/map?mylocation).

## Setup

The best way to start using this app is to clone the project into your local machine's project directory.

1. `cd ~/projects && git clone https://github.com/daveschumaker/local-air.git`
2. `cd local-air && npm install`
3. Rename `config-example.js` to `config.js` and enter appropriate details. You can find the ID for the PurpleAir sensor closest to your house by visiting the [PurpleAir map](https://www.purpleair.com/map?mylocation).
4. Run project using either `npm run dev` or `npm run build && npm run start`
5. View the node app's webpage in your browser by visiting `http://localhost:3000` (PORT 3000 is default, you can change this later)

## Contributions

If you're interested in contributing to the codebase, thank you!
Pull requests are the best way to propose changes and I welcome your pull requests:

1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints using the project rules.
6. Issue that pull request.

Note that any contributions you make will be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project.
34 changes: 34 additions & 0 deletions bin/controllers/apiController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fetch from 'node-fetch';
import config from '../../config';
const { sensorId } = config;

const fetchData = async () => {
try {
if (!sensorId) {
console.log('Error: Missing sensorId inside config.js');
process.exit();
}

const endpoint = `https://www.purpleair.com/json?show=${sensorId}`;
const res = await fetch(endpoint);
const data = await res.json();

if (data.results && data.results.length > 0) {
/**
* In some cases, PurpleAir can return array of sensor data
* based on parent / child sensors. For my purposes, I only
* care about the parent sensor.
*/
return data.results[0];
} else {
return false;
}
} catch (err) {
console.log('Error fetching data');
console.log(err);

return false;
}
};

export { fetchData };
14 changes: 14 additions & 0 deletions bin/controllers/dataStoreController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { LocalStorage } from 'node-localstorage';
const localStorage = new LocalStorage('./dataStore');

const writeData = (key, data) => {
const jsonString = JSON.stringify(data);
localStorage.setItem(key, jsonString);
};

const getData = key => {
const dataToParse = localStorage.getItem(key);
return JSON.parse(dataToParse);
};

export default { getData, writeData };
43 changes: 43 additions & 0 deletions bin/controllers/notificationController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import nodemailer from 'nodemailer';
import config from '../../config';

const { enabled, EMAIL_TO, EMAIL_FROM, EMAIL_PASSWORD, EMAIL_HOST, EMAIL_PORT } = config.email;

const transporter = nodemailer.createTransport({
host: EMAIL_HOST,
port: EMAIL_PORT,
secure: true,
auth: {
user: EMAIL_FROM,
pass: EMAIL_PASSWORD
}
});

const initMailOptions = {
from: `Air Quality Alert <${EMAIL_FROM}>`,
to: EMAIL_TO,
subject: '',
html: '' // email body
};

const mailer = {
send({ subject, body } = {}) {
if (!enabled) {
return;
}

let mailOptions = Object.assign({}, initMailOptions);

mailOptions.subject = subject || 'Air Quality Alert';
mailOptions.html = `${body}`;

transporter.sendMail(mailOptions, error => {
if (error) {
console.log('Error: Unable to send email');
console.log(error);
}
});
}
};

export default mailer;
Loading

0 comments on commit e132c57

Please sign in to comment.