-
but I'll need to be educated on why the current breakout boards are
not already the heart of a PLC.They could most certainly be the heart of a PLC. I guess the problem is that I've got an idea, but not a detailed and solid plan. Neither do I have extensive knowledge about electronics ;-) Especially the modular setup looks complicated... Found this thread about serial communication between Pico's, which could be useful.
@allObjects thanks for the tip!
-
Over the last year, I have been thinking about home automation on a higher level then Sonoff (limited lifetime) or 433mhz (limited possibilities) or even wifi (stability issues). Serious automation is usually done with a PLC (Programmable Logic Controller). These come with a price-tag: a Wago PLC with software license easily sets you back € 600. Cheaper options include a Railduino or Controllino, but as the name suggests, these have to be programmed with the Arduino IDE. I guess I just miss the ease of an Espruino PLC :) How cool would it be to program a PLC with something like this:
var ledDriver = plc.add('analogOut', A1); var ledDimmer = plc.add('rotary', { pinA: D1, pinB: D2, pinSw: D3, function () { ledDriver.setVoltage( E.clip(this.position, 0, 10) ); });
The PLC should have an ethernet-port (not wifi) to interface with (for example) Home Assistant, spitting out JSON over a websocket when the plc-class runs an event (like spinning the rotary, in the example above). And the other way around: the plc-class should be accessable over the websocket by feeding it JSON.
For future expansions, I would opt for a module based system: a main CPU in a plastic case with a small number of inputs and outputs (analog and digital), and optional modules for specific purposes (4 x input, 4 x output, 0-10v output...). The modules would connect to eachother with a USB-like connector system.
Gordon, any chance of an Espruino PLC happening? Or even a native ethernet Espruino? I would buy (both!) ;-) Untill that time, it seems that an Espruino Original could do pretty much everything I want it to, when combined with a WIZ550io. Does that still require the special build, even though the CC3000-support was removed from Espruino (and the lack of memory should no longer be an issue)?
Any thoughts on this would be appreciated!
-
Benchmarked and... well done MaBe :)
A full report can be found @ my Tweakblog, which is dutch but translate pretty accurate using Google.
-
-
See my dutch (mostly) Espruino blog @ https://thijsmans.tweakblogs.net/, or translate it using Google!
-
@allObjects Thanks for the intel on possible future enhancements ;) I doubt though if setting a static IP on the AP-side will speed up things. It doesn't change the DHCP-negotiation as such, as far as I know, but just returns the same IP all of the time.
Thanks @MaBe, I'll look into it! Unfortunately, my AP automatically jumps channels, depending on other network signals. So using a particular channel won't work. The BSSID sounds promising though (or would this only help in a situation with multiple AP's sharing one SSID?).
-
So I found this threat where wifi.setIP() was implemented to set a static IP for an ESP8266. These docs mention "You must be connected to an access point to be able to call this successfully". I thought I misinterpreted it, because: why setting a static IP once connected? Turns out the documentation is right: calling wifi.setIP() before connecting to wifi, does nothing. Calling it once connected actually changes the IP-address.
I want to get rid of DHCP in the first place. I'm building a battery-fed deep sleep project. DHCP is terribly slow and takes around 4 seconds (which is 40% of the total time needed for measuring and transmitting the results).
Any thoughts on this?
-
I got past the 8-bits vs 16-bits issue and I was just listening to my first song on the si4703; Phil Collings I believe...
/* si4703 begins reading from register upper register of 0x0A and reads to 0x0F, then loops to 0x00. Since register 0x0A comes in first we have to shuffle the array around a bit. */ si4703.prototype.readReg = function ( verb ) { //this.i2c.writeTo( this.addr, 0 ); data = this.i2c.readFrom( this.addr, 32 ); for( var i=0; i<data.length; i+=2 ) { bits = data [ i ] << 8; bits |= data[ i+1 ]; reg = ( i < 12 ? i+(10-i/2) : (i/2)-6 ); this.registers[reg] = bits; } if( verb !== false ) this.printReg(); }; /* Write the current 9 control registers (0x02 to 0x07) to the Si4703. It's a little weird, you don't write an I2C addres, The Si4703 assumes you are writing to 0x02 first, then increments. */ si4703.prototype.writeReg = function () { bytes = []; for( i=0x02; i<0x08; i++ ) { var high = this.registers[ i ] >> 8; var low = this.registers[ i ] & 0x00FF; bytes.push(high, low); } this.i2c.writeTo( this.addr, bytes ); }; si4703.prototype.printReg = function () { console.log( 'Register | Dec | Hex | Bits'); fill = String('.'); for( var i in this.r ) { label = i; dec = this.registers[ this.r[i] ]; hex = dec.toString(16); bits = dec.toString(2); console.log( label + fill.repeat(10-label.length ) + ' | ' + dec + fill.repeat(6-String(dec).length) + ' | ' + hex + fill.repeat(5-hex.length) + ' | ' + fill.repeat(18-bits.length) + bits ); } console.log(" "); };
This is working just fine:
Register | Dec | Hex | Bits DEVIDEID.. | 4674.. | 1242. | .....1001001000010 CHIPID.... | 2640.. | a50.. | ......101001010000 POWERCFG.. | 50433. | c501. | ..1100010100000001 CHANNEL... | 0..... | 0.... | .................0 SYSCONFIG1 | 6144.. | 1800. | .....1100000000000 SYSCONFIG2 | 21.... | 15... | .............10101 SYSCONFIG3 | 0..... | 0.... | .................0 TEST1..... | 48132. | bc04. | ..1011110000000100 TEST2..... | 6..... | 6.... | ...............110 BOOTCONFIG | 1..... | 1.... | .................1 STATUSRSSI | 28693. | 7015. | ...111000000010101 READCHAN.. | 205... | cd... | ..........11001101 RDSA...... | 255... | ff... | ..........11111111 RDSB...... | 0..... | 0.... | .................0 RDSC...... | 0..... | 0.... | .................0 RDSD...... | 0..... | 0.... | .................0
So now onwards to an Espruino-port of the Arduino sketch!
-
@allObjects: Perhaps I should have mentioned that I left the volume control out for the moment, since there is no sound to control yet :)
@Gordon: you make some excellent points on 8 vs 16-bits. I'll have a look at DataView, and some YouTube tutorials on bitwise operators ;-)
-
Okay, I've been breaking my head over this. There is a datasheet and an extensive programming guide available, but both assume you are able to interface with the si4703 :/
I'm using the Arduino-sketch as a guide line:
function si4703 ( option ) { this.addr = 0x10; this.reset_pin = option.res; this.data_pin = option.dat; this.clock_pin = option.clk; this.sen_pin = option.sen; this.registers = new Uint16Array(16); } si4703.prototype.init = function () { pinMode(this.reset_pin, 'output'); digitalWrite( this.reset_pin, false ); pinMode(this.data_pin, 'output'); digitalWrite( this.data_pin, false ); digitalWrite( this.reset_pin, true ); this.i2c = I2C1; this.i2c.setup( { scl: this.clock_pin, sda: this.data_pin } ); this.readReg(); this.registers[ 0x02 ] = 0x4001; // enable IC this.registers[ 0x07 ] = 0x8100; // enable oscillator this.writeReg(); this.readReg(); }; si4703.prototype.readReg = function () { this.i2c.writeTo( this.addr, 0 ); data = this.i2c.readFrom( this.addr, 32 ); for( var x=0x0A; ; x++ ) { if( x == 0x10 ) x=0; this.registers[x] = data[x] << 8; this.registers[x] |= data[x]; if( x == 0x09 ) break; } console.log( this.registers ); }; si4703.prototype.writeReg = function () { for( var i in this.registers ) { if( i > 0x02 ) this.i2c.writeTo( this.addr, i, this.registers[i] ); } };
So,the init-method should read the registers, update a few things (mainly the ENABLE-bit), and read the registers again. However, there is no change in the actual registers (first line is the output at startup, second line is after attempting to write the new values):
new Uint16Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4626, 16962, 2056, 0]) new Uint16Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4626, 16962, 2056, 0])
What am I missing?
-
Yes I'm aware of that. I thought the datasheet stated an input rise and fall time of 10ms. That's why I chose the digitalPulse anyway - creating a cueue would be too much of a hassle. However, reading the datasheet again, I see it says 10 ns :) I guess a double-digitalWrite should be fine.
I guess the first step for interfacing with the si4703 is getting the registers out one by one, using the subaddress-examples found here. I'll let you know when I get lost...
-
Our kitchen radio recently died, so I bought a si4703 i2c FM receiver. In about two years time, we'll be able to get some tunes in our kitchen again ;) I don't know a thing or two about bitwise JS, so reading the registers from the si4703 and overwriting them will be a pain... Reading tips are much appreciated!
However, the good news is that I got the rotary encoder and digital potentiometers for tuning and volume working! Both needed a new module: the existing Encoder-module doesn't cover the push-button my encoders have built into the shaft, and there was no existing module for my potmeters (X9C103).
I'm leaving them here in case anyone finds it useful. Also, remarks about coding is welcome, since I'm not a pro coder. Full modules are attached, here is a usage example:
var pot = new X9C103( { cs:PIN_CS, ud: PIN_UD, inc: PIN_INC } ); var volume = new Rotary( PIN_A, PIN_B, PIN_SW ); volume.rotateCallback = function () { if( this.position < 0 ) this.position = 0; if( this.position > 100 ) this.position = 100; pot.jumpTo( this.position ); };
-
Turns out the problem was not with the ESP01 or with Espruino, but with my malformed request :) The debugging methods from this thread made that clear (it showed a HTTP-400 header coming back).
For whoever finds it useful, this is how Espruino connects to Home Assistant:
var wifi = require("Wifi"); var entity = 'smoke_kitchen'; wifi.connect("SSID", {password:"PASS"}, function (e) { if( ! e ) { wifi.setHostname("SmokeAlarm-"+entity+"_"+getSerial() ); var http = require("http"); var data = JSON.stringify( {state:'on'} ); var options = { host: 'HASS-HOST', port: 8123, path: '/api/states/input_boolean.' + entity, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': data.length, 'x-ha-access': 'Token if needed', }, }; var req = http.request( options, function (res) { console.log('Status: ' + res.statusCode); console.log( res ); }); req.write( data ); req.end(); } else { console.log("Error connecting to wifi: ", e ); } });
-
I am trying to hook up an ESP01 to my smoke alarm like in this video
and making it report to home-assistant, running on my pi. Home-assistant has an API which should make it possible for the ESP01 to alter a variable (input_boolean) and trigger other alarms.However, the http-request only seems to be able to reach the pi on port 80. Which is a problem, since home-assistant listens to port 8123 (in my case, pihole listens to port 80).
var wifi = require("Wifi"); wifi.connect("SSID", {password:"PASS"}, function(e) { if( ! e ) { wifi.setHostname("SmokeAlarm-"+getSerial() ); wifi.stopAP(); var options = { host: 'xd-1', port: 80, path: '/api/', method: 'GET' }; require("http").request( options, function (res) { res.on('data', function (data) { console.log(data); }); }).end(); } });
The path "/api/" does not exist on port 80 (pihole only uses /admin/*) and the ESP01 outputs the right error page, served by pihole. The script functions as it should.
The path "/api/" DOES exist on port 8123 - I can see it in any browser on any device in my network. When changing the port from 80 to 8123, the ESP01 shows nothing, except "=undefined".
I'm starting to lose it. Why is the request not coming through? Any thoughts?
Thanks for all thoughts! I have done some thinking about hardware and code. About the hardware:
the Railduino and Controllino setup makes me somewhat uncomfortable. The devices are directly connected to 230 Volts. Through relays, but still... I prefer using seperate DIN-rail mounted relays like Wago, Finder, Siemens... Is this why your channels are 3-18v as well, @Gordon ?
These use 12V/24V for inputs (pretty standard, PLC-wise), which a GPIO does not supply. I'll go for Darlington-transistors switching a 12V-line.
No matter the board, the number of GPIO's is always a limitation for a PLC. I'll use shift registers for outputs (to drive the Darlington-transistors).
I've been looking into i2c-port expanders, but in my experience, these work too slow for high speed inputs like rotary encoders.
For inputs I'll use opto-couplers, to prevent blowing up the microcontroller with 12V :)
I'm planning on doing 0-10V outputs for dimmable LED-drivers, I guess using an op-amp is the way (not familiar with those yet).
As for as the actual javascript, I'm using several classes (* = not started yet, waiting for parts):
The 128x64 oled was a tad too small, a 320x240 LCD is in the mail. By using a seperate class with standard functions (mainly .bootscreen() and .update() ), changing the screen should be fairly easy. Hell, you could connect different screens at the same time, if you want to.
About the modular setup, mentioned before... Let's see how a single unit works out first ;)