Avatar for Jurand


Member since May 2018 • Last active Jul 2024
  • 6 conversations

Once a grandmaster in the noble art of Pixel-Wrangling and Font-Finessing, with a venerable 15-year reign over the kingdoms of Computer Graphics and DTP Operations, I found myself at a crossroads in the grand year of 2016. In a move that shocked the masses (or at least my cat), I hung up my virtual brushes and laid down my rulers, embarking on a quest most daring. I traded the safety of my artistic haven for the wild, untamed lands of Programming, seeking to don the mantle of a Software Engineer.

Yes, you read that right. After a decade and a half of making the digital canvas my domain, commanding armies of pixels with the ease of a seasoned general, I decided to confront the final boss: Code itself. Like a wizard choosing to forsake his magical staff for the arcane secrets of another realm, I plunged headfirst into this new adventure.

And so, here I stand (or sit, given the nature of the job), a transformed entity. I am no longer just the artist who could make your photos pop and your layouts sing but also the engineer who weaves logic and creativity into a tapestry of code. From visual maestro to software sage, my journey has been nothing short of a quest for the ages, chronicled here for your reading pleasure.

Most recent activity

  • in ESP32
    Avatar for Jurand

    But this is JS in IoT!
    Completely crazy ass thing :) no competition there.

    1. make affordable pricing options for business use, costs will be passed onto the clients, so it's important that this pricing remains accessible for small businesses and startups, ensuring that the cost doesn't become a barrier to entry, there could also be an option to contact you for a custom license to negotiate for like 1000+ devices or something, and if you think $5 will not work, make it $1 and name it "support for the project" and see what happens, result may surprise you,
    2. turn your boards to license-free by default for business use,
    3. make statement, that any solution sold with an invoice or receipt dated before the launch of the dual licensing model is considered to have a valid license
  • in ESP32
    Avatar for Jurand

    Have you considered adopting a dual licensing model? You could offer a full-functionality open-source community edition that's free for everyone, alongside a commercial license for businesses. This approach has been successfully used by others, such as LightGallery: https://www.lightgalleryjs.com/license/

    By doing this, you can continue supporting the open-source community while also creating a revenue stream from commercial users who need additional features or support.

    One crucial recommendation is to avoid setting payment terms on a monthly or yearly basis, as this scares people away. Instead, consider offering lifetime or per-project licenses, which are generally more acceptable.

    If the Espruino project evolves into a highly reliable piece of software that stands out in competition with others like MicroPython, particularly by proving to run faster or offering other significant advantages, it could certainly become worth paying for.

    Feature requests (ideas) to stand in that race:

    1. MP is threading capabilities with common data store (variables can be declared in a global scope and accessed across multiple threads). MP on the ESP32-S3, which is a dual-core processor, does support real threading using the _thread module. This allows you to run threads on separate cores, enabling true parallel execution of threads.
      Would it be possible to have it in Espruino?
    2. Creating a JavaScript bytecode compiler
      MP can be compiled to bytecode:
      Since '.mpy' files are precompiled, MP runtime can execute them directly without the overhead of parsing and compiling the code at runtime. Have you thought of making Espruino able to execute precompiled bytecode? I guess compiling Espruino directly to machine code involves substantial complexity due to the dynamic nature of JS, but maybe creating a JS bytecode compiler would be easier? Modifying the Espruino interpreter to execute this bytecode could offer a balance between improved execution performance and manageable complexity, making it a practical enhancement for the Espruino platform.
  • in ESP32
    Avatar for Jurand

    C5 is new, and I can't find any boards on Ali with it but it is the first RISC-V MCU that supports 2.4 and 5 GHz dual-band Wi-Fi 6, along with Bluetooth 5 (LE) and IEEE 802.15.4 (Zigbee 3.0, Thread 1.3) connectivity.

    It is designed for applications that require high-efficiency wireless transmission.

    ESP32-C5 has a 32-bit single-core processor which can clock up to 240 MHz in speed.
    It has a 384 KB on-chip SRAM along with external PSRAM support, 320 KB of ROM.

    So cool :)

  • in ESP32
    Avatar for Jurand

    C3 and C6 boards from Waveshare have RGB led :)

  • in ESP32
    Avatar for Jurand

    This run never ends. But that's good. We have new toys to play with from time to time :)

  • in ESP8266
    Avatar for Jurand

    I found out, that it works for me only when I use WebIDE: https://www.espruino.com/ide/
    When I use Chrome Extension or local IDE for some reason it does not add modules.
    Maybe it is my VPN, maybe there is some other problem.
    But I am glad that WebIDE works at least.

  • in ESP8266
    Avatar for Jurand

    I wanted to share with you where I ended with my research how to send data securely over untrusted unsecured networks using only http and sha1 - because that is all we have on those limited in memory boards. And that is what I've got.

    KEY is the same on ESP and API used only to calculate SHA1.
    API calculates SHA1 from data + KEY and compares it to signature.
    If it is the same - that is our board.

    Also it is good to have Date.now() somewhere in data to prevent API from being hacked and receive multiple copies of the same correct request. Date will prevent adding duplicated data to DB with the same date.

    CLOAK is used to have little more complex API endpoint route than some obvious one.

    If this helps someone, I'd be glad that I could help :)

    Big thanks goes to CanyonCasa for the idea: https://forum.espruino.com/comments/1346­2885/

    const crypto = require('crypto');
    const http = require('http');
    const wifi = require('Wifi');
    const KEY = 'e6a7b3d2-18f4-4c2b-9d67-4f5e1c7a8b3d';
    const HOST = 'someapithing.com';
    const API_VERSION = 'v2';
    const CLOAK = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
    const LOCATION = 'see-3';
    const NAME = 'oh-7';
    // Salt
    const generateSalt = (minimumLength, maximumLength) => {
      if (minimumLength < 1 || maximumLength < minimumLength) {
        throw new Error('Invalid length range: minLen must be >= 1 and maxLen must be >= minLen');
      const characters = '0123456789abcdef';
      const charactersLength = characters.length;
      const range = maximumLength - minimumLength + 1;
      const saltLength = minimumLength + Math.floor(Math.random() * range);
      let salt = '';
      for (let i = 0; i < saltLength; i++) {
        salt += characters.charAt(Math.floor(Math.random­() * charactersLength));
      return salt;
    // Send Data Securely
    const sendData = data => {
      // Prepare data
      data.salt = generateSalt(16, 16);
      data.location = LOCATION;
      data.name = NAME;
      const stringifiedData = JSON.stringify(data);
      const signature = crypto.SHA1(stringifiedData + KEY).toString('hex');
      const stringifiedDataWithSignature = JSON.stringify([
          data: data,
          signature: signature,
      // Send
      const options = url.parse(`http://${HOST}/${API_VERSION}­/${CLOAK}/device`);
      options.method = 'POST';
      options.headers = {
        'Content-Type': 'application/json',
        'Content-Length': stringifiedDataWithSignature.length,
      const req = http.request(options, res => {
        console.log(`[ STATUS ] ${res.statusCode}`);
        let data = '';
        res.on('data', chunk => (data += chunk));
        res.on('end', () => console.log('[ END ]'));
      req.on('error', err => console.error('[ ERROR ]', err));
      req.on('close', () => console.log('[ CLOSE ]', data));