Moddable-OpenSource / moddable

Tools for developers to create truly open IoT products using standard JavaScript on low cost microcontrollers.
http://www.moddable.com
1.29k stars 235 forks source link

Sending Pulse Waves #552

Closed louisvangeldrop closed 3 years ago

louisvangeldrop commented 3 years ago

I want to control my home appliances using the rf433 protocol. The RF433 protocol is using pulses in the order of 200 microseconds. Reading in Javasscript is due to performance problems unfortunately not possible. However sending these pulses is also not possible for the same reason. Sending a pulsetrain to switch on my light-bulb is a pulse-wave with different pulselengths per state. Roughly 140 alternating pulses varying in length between 250 usecs to a multiple of 250 usecs. To overcome this performance problem in Javascript, Espruino uses the digitalPulse function, Pigpiod uses a Wave-transmit option. Both options accept an array of pulselengths to send a pulse High/Low. Unfortunately I have missed this option in Modable. (I hope I have made a mistake in not finding it).

Maybe the IO-specification has this option, but I have skipped IO, since it only available for the ESP8266. A nice and cheap MCU, but I believe ESP32 is the direction to go.

wilberforce commented 3 years ago

For the ESP32 the RMT driver would be the way to go. The onewire driver uses this - this might be a help to doing a RF433 driver:

https://github.com/Moddable-OpenSource/moddable/blob/public/modules/drivers/onewire/esp/owb_rmt.c

wilberforce commented 3 years ago

This might be of use: https://github.com/sui77/rc-switch/blob/master/RCSwitch.cpp

louisvangeldrop commented 3 years ago

@wilberforce , Thx for your suggestions. I already have a Javscript/nodejs-based solution ( -transpile of VHDuino). It works perfectly on a Raspberry-Pi3. For some parts of my house, the switches are too far away ( -thick walls) it doesn't work. I tried Espruino at an ESP32 ( ESP8266 is too limited ) using MQTT for receiving the commnands and a digitaPulse to xmit the pulses to the devices. However Espruino is by far too unstable for this solution. Then I found the -wellhidden Moddable solution, but unfortunately I miss the digitaPulse option/wave-pigpiod option. As you can see from the rcswitch, all protocols work at 100+microsecond level. Maybe this explanation helps for better understanding the problem. I have no knowledge of C or C++. I program in Typescript and hope that once an IOT compiler for Typescript will appear. Makecode looks very interesting, but lacks support for ESP32.

phoddie commented 3 years ago

@louisvangeldrop - I recall doing some work to create RMT bindings for the ESP32 while back. Based on the notes from @wilberforce, it sounds like that is about what you need here. I'll try to find that code and see if it might be applicable / adaptable here.

If you don't mind, I have a couple of questions. You say Espruino is "far too unstable." I've not used it much. Can you elaborate on that a bit. You also say that Moddable is "well hidden." ;) But, here we are! What could we have done to be more visible to you? Thanks.

barbiani commented 3 years ago

@Peter Hoddie peter@moddable.tech I have that rmt implementation you did for me. Will attach it here later tonight.

On Mon, Feb 1, 2021, 18:38 Peter Hoddie notifications@github.com wrote:

@louisvangeldrop https://github.com/louisvangeldrop - I recall doing some work to create RMT bindings for the ESP32 while back. Based on the notes from @wilberforce https://github.com/wilberforce, it sounds like that is about what you need here. I'll try to find that code and see if it might be applicable / adaptable here.

If you don't mind, I have a couple of questions. You say Espruino is "far too unstable." I've not used it much. Can you elaborate on that a bit. You also say that Moddable is "well hidden." ;) But, here we are! What could we have done to be more visible to you? Thanks.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Moddable-OpenSource/moddable/issues/552#issuecomment-771176507, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYLTJF2TS2JQSF3E623FJ3S44NMDANCNFSM4WZH2QEQ .

phoddie commented 3 years ago

@barbiani - Ha! Thank you! I found it just now too! It looks like @andycarle addled receive support at some point too. I will post it to a Gist shortly.= so @louisvangeldrop can try it. If it works well, we can merge it (finally...) into the Moddable SDK.

phoddie commented 3 years ago

@louisvangeldrop - Here's the RMT Gist. It is a small project that includes both the RMT module and a simple write test.

andycarle commented 3 years ago

Ah, yeah, I added the receive functionality to that when I was doing NEC IR Protocol work. It was working well as of... 18 months ago or so. Haven't tried it since!

louisvangeldrop commented 3 years ago

@phoddie - The Esp32-Espruino is unstable due to Wifi-problems. The business-model of Gordon Williams doesn't allow him to spend time to fix this issue. I understand and accept that completely. I admire the work he is doing for Espruino and have a great respect for his achievements. With respect to "well-hidden". I have been Googling a lot for ESP32 and Javascript solutions. I have found espruino, low.js, jerryscript and mongoose. Maybe the search results here in the Netherlands ( Europe) are different compared to the States. I have found Moddable by searching for IOT, ESP32, Makecode and Typescript, if I remember well. It was more than 1-2 months ago. As mentioned before "being listed at ESP32.com" would certainly help.

louisvangeldrop commented 3 years ago

@andycarle - Is the divider used during writing? And are the pulsetimings in microseconds?

louisvangeldrop commented 3 years ago

I get the foolowing error: C:\Users\louis\OneDrive\Apps\Repos\IoT\Moddable\Example1\rmt.c (146) # Break: RMT: install failed!

Do I miss a driver?

phoddie commented 3 years ago

Are you running the example as-is or something else? It would help to know. (FWIW - I ran the example this morning and it works as expected -- blinking the LED on a Moddable Two)

louisvangeldrop commented 3 years ago

As-is on a esp32/m5atom_matrix

louisvangeldrop commented 3 years ago

I am running now on a NodeMCU ESP32 DEvit and it blinks the LED

phoddie commented 3 years ago

Interesting. Perhaps something on the Matrix is grabbing the RMT channel 0 -- probably the neopixels driver.

You can specify the channel to use in the dictionary passed to the constructor. There are 8 available. Try channel 1 on the M5 Atom Matrix?

let a = new RMT({pin: 2, channel: 1, divider: 255});

(If I recall well @barbiani advocated allocating channels automatically. That would solve this conflict, but is more complicated to safely implement in a general way.)

louisvangeldrop commented 3 years ago

At the moment I "solved" the microseconds-delay function by doing:

var usleep = (us) => { // us in microseconds let endTime = Time.microseconds + us while (Time.microseconds < endTime) { } }

It is ugly, but it works.

phoddie commented 3 years ago

It is ugly. Why is it necessary? (I didn't find the problem statement above.)

phoddie commented 3 years ago

Above you wrote:

I program in Typescript and hope that once an IOT compiler for Typescript will appear

You do know that the Moddable SDK has experimental support for TypeScript? It is introduced in this blog post. Summary:

louisvangeldrop commented 3 years ago

@phoddie . I wonder what the exact spec's of the RMT module are. How/when to use the divider and are the timimgs in microseconds? At the moment I only use the write function.

I have implemented a copy of the Espruino digitalPulse in Typescript and used the usleep function in the ugly cpu-loop way. Of course a sleep-based usleep would be a better solution.

When using Typescript I have errors in some typedefinition files, which are difficult to solve, but do not prohibit the typescript compiler to generate the javascript files . However these errors block the mcconfig procedure. It would be nice to be able to specify that a tsc-compile error will not block the mcconfig procedure.

phoddie commented 3 years ago

I wonder what the exact spec's of the RMT module are

The RMT module is a very light wrapper on the native RMT API in the ESP-IDF. The definitive source of information on that is the Espressif page here.

I have implemented a copy of the Espruino digitalPulse in Typescript and used the usleep function

Cool! FWIW - You haven't explained why a synchronous usleep is necessary. Since the RMT module can queue up a large number of transitions with very precise timing, it seems like it could be used instead.

It would be nice to be able to specify that a tsc-compile error will not block the mcconfig procedure.

Are you suggesting to treat all errors generated by the TypeScript compiler as only a warning, or is there some way to distinguish between warnings and real errors? I don't have much experience with TypeScript: Is there a compiler flag to request this behavior?

louisvangeldrop commented 3 years ago

@phoddie I agree with your suggestion that RMT is the way to go. It is close to the pigpiod Wave-functionality, that I use at my Raspberry Pi3 nodejs solution. Now I have to look how to use it with my current software, since it requires some knowledge of C++. Not so happy to do that, since I was looking for Java/Type-script solutions, because I don't want to learn C++.

In one of my previous posts I mentioned the unreliabilty of ESP32 Espruino/Wifi solution. It turns out that Wifi ESP32 is unreliable. I can run my current solution for several hours and suddenly the connection is lost and difficult to restore. ESP32 may also loose the Wifi-connection several times per hour completely at random. Will further investigate how to solve that.

Typescript: with respect to Typescript return codes, I believe there is an open issue how to solve that. Maybe a TSConfig option or a cli-switch.

phoddie commented 3 years ago

@louisvangeldrop - I don't understand. The RMT JavaScript module is a direct interface to the native RMT functionally. You don't need any knowledge of C++ to use it.

louisvangeldrop commented 3 years ago

@phoddie - I try to find out what the values 32000*9, 32000, ..... exactly do. I could not find that without going to the ESP32 RMT library.

louisvangeldrop commented 3 years ago

@phoddie Already found the meaning of the divider in transmission mode. When set to 80, the pulses to be sent are in microseconds.

wilberforce commented 3 years ago

@louisvangeldrop I saw in your path that you are building in the one drive folder.

This will be slow as there are a lot of small files and every time you change one of them it will sync to one drive. Either disable so one drive doesn't sync - or move out of the onedrive tree..

louisvangeldrop commented 3 years ago

@wilberforce - You are 100% right. I always pause Onedrive, when developing. It was my intention to use Onedrive as my network drive. I have a 1 gbps internet connection, but the small files kill the performance of Onedrive. During the day I pause Onedrive and resume at the end of the day.

wilberforce commented 3 years ago

@louisvangeldrop I tried to work this way once - to sync projects between a laptop and desktop.

I found moving my projects to github simplified everything. Work on desktop - push - and then on laptop pull and visa-versa

louisvangeldrop commented 3 years ago

@wilberforce - I firstly started with Azure Source Management services. But as soon as VSCode supported Github, I transferred everything to Github.

I prefer to have one hardware independent IOT-layer ( I believe/hope that will be wasm+wasi). The reason is that I started with Arduino, moved to Espruino/Esp8266, Nodejs, Makecode etc.. What an IOT helll. All these solutions lack a generic layered architecture, every solution at its own island. Different libraries, performance problems, reliabilty problems, setting up mesh with interrelated problems. Nice if everything works, but if one item fails, the whole project falls apart. And at last continuity challenges. At the other hand , I hope that Moddable's Wasm+wasi option will bring the structure I am looking for.

My apologies for showing too much of my frustations.

louisvangeldrop commented 3 years ago

@phoddie - I can't achieve the following with rmt in the writable function: a.write(1,[pulse array]) a.write(0,[1,1]) // switch the pin off, otherwise all 433 mhz communcations is lost

The last write results in th error: pin not writable.

@Marketing. Please make an Moddable exension in VSCode for making development in Typescript easier. With the huge development eco-system of VSCode, developers will find your beautifull solution. I just installed the ESP-IDF extension for VSCode and installed all the software required. Straightforward and after the installation, the migration of the Moddable ESP32 software worked like a charm.

phoddie commented 3 years ago

@louisvangeldrop - That's correct. The ESP-IDF allows one RMT write operation at a time. When one completes, you can begin the next write. The Moddable SDK follows this behavior as it uses the rmt_write_item API from the ESP-IDF.

The example shared shows how to use the onWritable callback of the RMT to receive the notification that the write has completed. You might rework your example as follows:

a.write(1,[pulse array]);
a.onWritable = function() {
   a.write(0,[1,1]);
}

As an alternative, depending on how your application is organized, it might be feasible to merge the two writes by appending the values from the second write to the pulse array.

louisvangeldrop commented 3 years ago

@phoddie - The following code works:

const rmtPin = new RMT({ pin: 5, channel: 0, divider: 80 });

var delayms = ms => new Promise(r => Timer.set(r, ms));

rmtPin.onWritable = () => { }

var writeAsync = async (pulses, value = 1) => { if (value === pulses.length % 2) pulses.push(10) // last write must be LOW write rmtPin.write(1, pulses) await delayms(400 + 0.001 * pulses.reduce((a, b) => a + b)) }

phoddie commented 3 years ago

Using a timer to pace the output instead of the callback from the RMT seems less precise and more complex. But, I'm glad you have a solution that works for your needs!

As we've addressed the original topic of this issue (and several others) I'm going to close this.

louisvangeldrop commented 3 years ago

@phoddie - THX for the support. BTW with the latest 4.2 version of ESP_IDF, I have the feeling that the wifi-problems- that I have encounterd here , are solved.

louisvangeldrop commented 3 years ago

Final code with await/async:

const rmtPin = new RMT({ pin: RMTOptions.pin, channel: 0, divider: 80 }); // GPIO 2, RMT channel 0, clk_div 1- 255

var writableAsync = async (rmt) => new Promise(r => rmt.onWritable = r)

var writeAsync = async (pulses, value = 1) => { if (value === pulses.length % 2) pulses.push(10) // last write must be LOW write rmtPin.write(1, pulses) await writableAsync(rmtPin) }

var loop = async () => { while (true) { await writeAsync(tlOff) await writeAsync(tlOn) } } loop()

phoddie commented 3 years ago

Nice. That looks better without the timer.