Hi,

the "function Switch" is a build plan for an object, that has a method
setState. This method will be defined in the constructor method of the
Switch, because you will use variables, which are hide from the outside,
by defining them in the constructor.

By here there is no need to do it so, because there are no such
mechanism. Thats why it is better to use the prototype object, to define
these. The benefit is, that the parser won't create multiple copies of
the same function like he will in this example. You save memory and
speed your application a little bit up.

function Switch() {
        ...
}

Switch.prototype.setState(state) {
        ...
}

Switch.prototype.toggle() {
        ...
}

What does the setState?

The first line of the setState is a shortcut for an if statement.

var str = state === "on" ? onString(this.id[2]) : offString(this.id[2]);

I use ES6, so I will link the syntax below:

let str;
if (state === "on") {
        str = onString(this.id[2])
} else {
        str = offString(this.id[2])
}

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/let


This is a little bit confusing, because the initial string is "sw".
These are two characters. If you ask the character on the second
position, you get an undefined for the default id value.

s - 0
w - 1

A better way is to check the string in the constructor method, split
them and handle the id as an integer.

The on and off strings could be merged to one function like

function getPyString(id, mode) {
        return './public/python/sw' + id + '_' + mode + '.py';
}

Back to set State. On str you have now the file to a python script,
which will be called. This is realy ugly, because if there is an error,
you will crash the server. Do not throw errors, if you're not using
Promises. The callback is called by the runtime, when the shell script
is finished and with no try/catch. That means an unhandled error.

>     PythonShell.run(str, function (err) {
>       if (!process.env.DEV){
>         if (err) throw err;
>       }
>     });
>     this.state = state

Ok, next. The writeFile should have a callback. Something could went
wrong and then no data will be stored.

Number 7: You have the to difference between your local file system and
the uri which will be created for your application server.

Express is a framework which handles your web application.
http://expressjs.com/
There you define routes to a functionality. If you read

/api/switches

that means that you create a route like

http://[ip or domain]/api/switches

your local file system is not affected by this.

You can toggle the lights by sending a post request to an light. This is
defined by:

app.post('/api/switches/:id', function(req, res) {

});

The req object is the object, which stores the information of your
request. http://expressjs.com/en/4x/api.html#req

And req.query means, that the get param is meaned.
Send a post request like this to switch your light on.

http://[Server:Port]/apiswitches/sw1/?password=test&command=on

I hope that clarifies the code a little bit. There are many things that
can improve the code, but I think this should be sufficient for this time.

Thomas


Am 18.04.2017 um 00:36 schrieb Marcio Valenzuela:
> Im working with this article:
> https://www.instructables.com/id/Google-Home-Raspberry-Pi-Power-Strip/
> 
> and in it they use this node.js app which serves as a control for light
> switches.  Im trying to understand this code in order to modify it for
> my purposes.  Here is the code and below is my understanding of it:
> 
> 1. creates an array
> 2. reads data from the saveState.json file
> 3. creates a Switch object with default sw as id, off as state and
> switch as name and creates a toggle function where if on then off and
> vv. I dont understand the this.setState bit?
> 4. some quirk
> 5. gets a switch
> 6. writes the switch array back to json
> 7. configures the server api route...i was wondering how we went from
> folder/app.js to ip/API/switches/
> 8. how do i toggle the switch on and off?
> 
> |
> require('dotenv').config();
> 
> const PythonShell = require('python-shell');
> const fs = require('fs');
> const express = require('express');
> const bodyParser= require('body-parser');
> const path = require('path')
> const app = express();
> 
> 
> // 1.Switch states held in memory
> const switches = [];
> 
> // 2.Read state from saveState.json, populate switches array
> var readableStream = fs.createReadStream('saveState.json');
> var data = ''
> 
> readableStream.on('data', function(chunk) {
>     data+=chunk;
> });
> 
> readableStream.on('end', function() {
>   var parsed = JSON.parse(data);
> 
>   for (i=0;i<parsed.switches.length;i++){
>     switches.push(new Switch(parsed.switches[i]))
>   }
> });
> 
> 
> 
> 
> // 3.Switch Model
> // Expects an object:{
>   // id:"sw" + number,
>   // state: "on" or "off",
>   // name: any name you want to display. Defaults to "switch"
> // }
> 
> function Switch(switchValues){
>   this.id = switchValues.id || "sw"
>   this.state = switchValues.state || "off"
>   this.name = switchValues.name || "switch"
>   this.toggle = function(){
>     if(this.state === "on"){
>       this.setState("off")
>     } 
>     else{
>       this.setState("on");
>     }
>   }
>   this.setState = function(state){
>     var str = state === "on" ? onString(this.id[2]) : offString(this.id[2]);
>     PythonShell.run(str, function (err) {
>       if (!process.env.DEV){
>         if (err) throw err;
>       } 
>     });
>     this.state = state
>   }
>   // Invokes setState on init to set the switch to its last recalled state.
>   this.setState(this.state);
> }    
> 
> // 4.needed due to a quirk with PythonShell
> function onString(number){
>   return './public/python/sw' + number + '_on.py'
> }
> function offString(number){
>   return './public/python/sw' + number + '_off.py'
> }
> 
> 
> 
> 
> // 5.Switch Lookup
> function getSwitch(string){
>   return switches.filter(function(element){
>     return element.id === string;
>   })[0]
> }
> 
> // 6.Updates saveState.json
> function saveState (){
>   var formattedState = {
>     switches: switches
>   }
>   fs.writeFile('./saveState.json', JSON.stringify(formattedState) )
> }
> 
> 
> //7.Server Configuration
> app.use(bodyParser.urlencoded({ extended: true }))
> app.use(express.static(__dirname + '/public'));
> 
> // If you have a frontend, drop it in the Public folder with an entry
> point of index.html
> app.get('/', function(req, res){
>   res.sendFile('index');
> })
> 
> // Switch Routes for API
> app.get('/api/switches', function(req, res){
>   res.send(switches);
> })
> 
> app.get('/api/switches/:id', function(req, res){
>   var found = getSwitch(req.params.id);
>   res.json(found);
> })
> 
> app.post('/api/switches/:id', function(req, res){
> 
> // 8.For now, uses a simple password query in the url string. 
> // Example: POST to localhost:8000/API/switches/sw1?password=test
>   if (req.query.password === process.env.PASS){
>     var foundSwitch = getSwitch(req.params.id);
>     
>     // Optional On / Off command. If not included, defaults to a toggle.
> 
>     if(!(req.query.command === "on" || req.query.command === "off")){
>       foundSwitch.toggle();
>     }
>     else {
>       foundSwitch.setState(req.query.command)
>     }
> 
>     saveState();
>     console.log("postSwitch "+JSON.stringify(foundSwitch));
>     res.json(foundSwitch);
>   }
>   else {
>     console.log("invalid password")
>     res.send("try again")
>   }
>   
> })
> 
> app.listen(process.env.PORT, function(){
>  console.log('Listening on port ' + process.env.PORT);
> })
> 
> |
> 
> The way to use it according to the author is that I post a request to
> that server as:
> 
> http://ip/API/switches/sw1?password=mypasswd
> 
> This prints out the json stored in the saveState.json file which is:
> 
> |
> {"switches":[{"id":"sw1","state":"off","name":"Kyle's Lamp"}]}
> |
> 
> where the python file for OFF for example is:
> 
> |
> # Edit line 6 to match your chosen GPIO pin
> 
> import RPi.GPIO as GPIO
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(23, GPIO.OUT)
> |
> 
> 
> and for ON its just a change to GPIO.IN
> 
> Thanks!
> 
> -- 
> Job board: http://jobs.nodejs.org/
> New group rules:
> https://gist.github.com/othiym23/9886289#file-moderation-policy-md
> Old group rules:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> ---
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected]
> <mailto:[email protected]>.
> To post to this group, send email to [email protected]
> <mailto:[email protected]>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/nodejs/92b0b89d-9841-43a8-9ff6-b2d9e527ac5a%40googlegroups.com
> <https://groups.google.com/d/msgid/nodejs/92b0b89d-9841-43a8-9ff6-b2d9e527ac5a%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

-- 
Job board: http://jobs.nodejs.org/
New group rules: 
https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/nodejs/ff6e46a8-b087-97d3-22a8-e001644b7999%40gmx.de.
For more options, visit https://groups.google.com/d/optout.

Reply via email to