-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e132c57
Showing
20 changed files
with
6,179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
config.js | ||
dataStore | ||
dist | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.