Miłosz Orzeł

.net, js/ts, html/css, arduino, java... no rants or clickbaits.

The Daily Grind (Quick Tips on Miscellaneous Issues, Ep. 4)

Intro

Here's a 4th round of random problems and quick tips for working around them (previous: 3, 21).

The issues:

 

CORS errors while fetching files from Firebase storage bucket

If you upload files to Firebase cloud storage you might be able to get them with curl or open directly through a link in a browser but it doesn't mean that your app will be able to fetch them. For that to work you need to setup CORS.

If you have some environment where CORS is already working as expected you can use gsutil command to obtain current settings with:

gsutil cors get gs://example1.firebasestorage.app > cors.json

and then apply the exported cors.json on another environment: 

gsutil cors set cors.json gs://example2.firebasestorage.app

You can obtain the gs:// link to your storage bucket on Storage page in Firebase Console:

Find the gs:// link. Click to enlarge...


If you don't have any cors.json yet, this might be a starter (you might want to tighten the origin).

[
  {
    maxAgeSeconds: 3600,
    method: ["GET"],
    origin: ["*"],
    responseHeader: ["Content-Type"],
  },
]

 

Leaking RTL styling in styled-components 5

If you are using styled-components 6 you can create styling that mixes conditional style blocks and [dir="rtl"] attribute selector for right to left text direction

Take this as example:

import styled, { css } from "styled-components";

const Text = styled.div<{ $first?: boolean; $last?: boolean }>`
  color: ${({ $first, $last }) =>
    $first ? "purple" : $last ? "green" : "unset"};
  margin: 5px;

  ${({ $first }) =>
    $first &&
    css`
      border: 1px solid purple;

      [dir="rtl"] & {
        border: 1px dashed purple;
      }
    `}

  ${({ $last }) =>
    $last &&
    css`
      border: 1px solid green;

      [dir="rtl"] & {
        border: 1px dashed green;
      }
    `}
`;

export const RtlTest = () => {
  return (
    <div style={{ border: "1px solid gray", margin: 20 }}>
      <Text $first>aaa</Text>
      <Text>bbb</Text>
      <Text $last>ccc</Text>
    </div>
  );
};

The RtlTest component aggregates 3 styled divs (Text components). Text applies different styles depending on $first and $last properties and it also varies style when page is in RTL mode.

styled-components 6 vs 5 comparison

In styled-components 6.0.0 it all works well but results get messy in version 5 (5.3.11 is the last last 5.x.x version):

Notice how the green dashed border styling, which is supposed to be only on Text instance with $last property, got applied to all Text instances! This happens because RTL styling for each conditional block goes to main sc- class and the last injected one wins.

This is simplified example but at work I've noticed it on complex component that applied some transform: rotate, and when such things start to add up you have some fun time debugging ;)

If upgrade to version 6 is not possible, you can avoid adding conditional blocks and instead inject custom attributes and write selectors that use these attributes:

import styled, { css } from "styled-components";

const Text = styled.div.attrs<{ $first?: boolean; $last?: boolean }>(
  ({ $first, $last }) => ({
    "data-first": $first || undefined,
    "data-last": $last || undefined,
  }),
)<{
  $first?: boolean;
  $last?: boolean;
}>(
  ({ $first, $last }) => css`
    color: ${$first ? "purple" : $last ? "green" : "unset"};
    margin: 5px;

    &[data-first] {
      border: 1px solid purple;
    }

    [dir="rtl"] &[data-first] {
      border: 1px dashed purple;
    }

    &[data-last] {
      border: 1px solid green;
    }

    [dir="rtl"] &[data-last] {
      border: 1px dashed green;
    }
  `,
);

export const RtlTest = () => {
  return (
    <div style={{ border: "1px solid gray", margin: 20 }}>
      <Text $first>aaa</Text>
      <Text>bbb</Text>
      <Text $last>ccc</Text>
    </div>
  );
};

With this approach styles that depend on property passed to Text component will not leak out in RTL mode.

 

Missing trace in console log wrapper

Let's say you want to create a custom logger that will automatically add a prefix to logged messages so you could easily spot logs coming from your code vs log entries added by some dependencies.

Here are two ways to do it:

const PREFIX = "[example]";

export const loggerWithoutBind = {
  log: (...args: unknown[]) => console.log(PREFIX, ...args),
};

export const loggerWithBind = {
  log: console.log.bind(console, PREFIX),
};

Both loggers will automatically prefix passed message and retain ability to add more data to log entries:

import { loggerWithoutBind, loggerWithBind } from "./logger.ts";

loggerWithoutBind.log("Lalala (without bind)", { a: "aaa", b: [1, 2] });
loggerWithBind.log("Lalala (with bind)", { a: "aaa", b: [1, 2] });

...but, the first one has a critical flaw. The entries will be marked as coming from the log wrapper function instead of the line that logged the message, which makes the trace/link useless:

Logger with and without bind. Click to enlarge...
The bind technique avoids this issue and should work in modern browsers (I've checked in Chrome and Firefox).

 

Header not found in Axios response interceptor

By the specs, HTTP header names are case-insensitive and you could use Fetch API get function to read headers in case-insensitive way.

For example, assuming that server added X-My-Example header with abc as value, you can read it both in original case and in lowercase:

// Fetch API
console.log(res.headers.get("x-my-example")); // abc
console.log(res.headers.get("X-My-Example")); // abc

If you list all headers names by:

console.log([...res.headers.keys()]);

You will see the names in lowercase...

Watch out though if you try to read the headers with Axios, for example in response interceptor:

// Axios
console.log(res.headers["x-my-example"]); // abc
console.log(res.headers["X-My-Example"]); // undefined

The names in Axios response headers object are normalized to lowercase!

Putting a commend with name in original casing may be good idea (one day you might run case-sensitive search/replace in client and server code)...

[OoB] Controlling Gun Turret With Spring Boot REST Service (Java/Arduino)

This is the fifth post in my little "Out of Boredom" series dedicated to hobby projects with Arduino. Previous posts were all .NET based:

Now it's time for a bit of Java!

I will show you how to use Spring Boot framework to quickly create RESTful web service that can receive JSON requests and send commands to Arduino. The aim is to control a servo and relay based gun turret such as this one:

Gun turret prototype... Click to enlarge...

Click here to get an idea of how such turret operates. The video shows a prototype based on ASG pistol. Don't worry, my aim is quite peaceful: I want to build paintball gun turret :)

I will not discuss any electronics setup or Arduino code in this post. Take a look at the articles linked above to see information about PC-Arduino communication, controlling servos and building relay based circuit... I assume that you know what Spring Boot is, but advanced knowledge is not required to follow this post.

Full code of the project is available on GitHub (includes both Java application and Arduino sketch)...

The easiest way to create basic working Spring Boot project is to use Spring Initializr. I started my project by filling the form like this:

Spring Initializr settings... Click to enlarge...

Note that Gradle is used to create (fat) Jar package, Java 1.8 is used and the only required dependency is Web. This setup will produce an application running on Tomcat Embedded so there's no need for installing any web server. The app has support for REST controllers so we will be able to handle JSON based communication in a clean way with very little effort...

 

Without further ado, here is the piece of code responsible for receiving messages from clients:

package springarduino;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TurretController {
    private final ArduinoConnection arduino;

    @Autowired
    public TurretController(ArduinoConnection arduino) {
        this.arduino = arduino;
    }

    @RequestMapping(value = "turret/execute", method = RequestMethod.POST, consumes = "application/json")
    public TurretResponse executeTurretAction(@RequestBody TurretRequest request) {
        if (request.getPan() < 0 || request.getPan() > 180) {
            throw new IllegalArgumentException("Pan out of 0..180 range (" + request.getPan() + ")");
        }

        if (request.getTilt() < 0 || request.getTilt() > 180) {
            throw new IllegalArgumentException("Tilt out of 0..180 range (" + request.getTilt() + ")");
        }

        boolean sent = arduino.controlTurret(request.getPan(), request.getTilt(), request.isFire());
        if (!sent) {
            throw new RuntimeException("Command not sent :(");
        }

        return new TurretResponse(request.getId(), "Command sent :)");
    }
}

TurretController class has @RestController annotation and a public method marked with @RequestMapping. The mapping specifies that executeTurretAction method should be invoked whenever a client makes a POST request to .../turret/execute URL. Any HTTP client capable of sending POST with Content-Type="application/json" can communicate with such Spring controller method. It can be some desktop application or a simple HTML page with a bit of jQuery for example. I was using Postman Chrome App to prepare requests. In the next post I will describe how to communicate with such controller from smartphone that runs PhoneGap/AngularJS based application...

executeTurretAction methods expects one argument of type TurretRequest:

package springarduino;

public class TurretRequest {
    private int id;
    private int pan;
    private int tilt;
    private boolean fire;

    // public getters and setters hidden for brevity
}

If client sends JSON payload such as this:

{
    "id": "311",
    "pan": "111",
    "tilt": "99",
    "fire": "true"
}

Spring will take care of creating TurretRequest object. Our service method returns TurretResponse:

package springarduino;

public class TurretResponse {
    private int id;
    private String message;

    public TurretResponse(int id, String message) {
        this.id = id;
        this.message = message;
    }

    // public getters and setters hidden for brevity
}

If everything goes well, this kind of data will be sent back to client:

{
    "id": 19,
    "message": "Command sent :)"
}

You don't have to do anything special to make this happen. Spring chooses HttpMessageConverter implementation to create response in a format that is expected by the client. Another nice feature of our @RestController is the error handling. Let's say that client provides invalid value of tilt angle - this is what is sent back as response:

{
    "timestamp": 1424382893952,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "java.lang.IllegalArgumentException",
    "message": "Tilt out of 0..180 range (222)",
    "path": "/turret/execute"
}

Such message is easy to handle in error callbacks (thanks to 500 HTTP status code) and contains useful properties such as message and exception.

Notice that arduino object of ArduinoConnection type is used inside executeTurretAction method. ArduinoConnecton is a Spring bean responsible for communicating with Arduino over serial port.

Our controller gets reference to proper object thanks to Spring's IoC container. TurretController constructor is annotated with @Autowired so Spring knows that ArduinoConnection object needs to be injected.

This is the class responsible for talking to Arduino:

package springarduino;

import gnu.io.NRSerialPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.DataOutputStream;

@Component
public class ArduinoConnection {
    private static final int MESSAGE_SEPARATOR = 255;

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Value("${arduinoPortName}")
    private String portName;

    @Value("${arduinoBaudRate}")
    private int baudRate;

    private NRSerialPort serial;


    @PostConstruct
    public void connect() {
        log.info("ArduinoConnection PostConstruct callback: connecting to Arduino...");

        serial = new NRSerialPort(portName, baudRate);
        serial.connect();

        if (serial.isConnected()) {
            log.info("Arduino connection opened!");
        }
    }

    @PreDestroy
    public void disconnect() {
        log.info("ArduinoConnection PreDestroy callback: disconnecting from Arduino...");

        if (serial != null && serial.isConnected()) {
            serial.disconnect();

            if (!serial.isConnected()) {
                log.info("Arduino connection closed!");
            }
        }
    }

    public boolean controlTurret(int pan, int tilt, boolean fire){
        try {
            // Actual values sent to Arduino will be in proper unsigned byte range (0..255)
            byte[] message = new byte[]{(byte) pan, (byte) tilt, (byte) (fire ? 1 : 0), (byte) MESSAGE_SEPARATOR};

            DataOutputStream stream = new DataOutputStream(serial.getOutputStream());
            stream.write(message);

            log.info("Turret control message sent (pan={}, tilt={}, fire={})!", pan, tilt, fire);
            return  true;
        } catch (Exception ex) {
            log.error("Error while sending control message: ", ex);
            return false;
        }
    }
}

@Component annotation is there to show Spring that ArduinoConnection is a bean and as such Spring should take care of its lifecycle and usage as dependency. By default Spring creates beans in singleton scope. This is fine for us - we only need one such object. connect method is marked with @PostConstruct. This makes the method an initialization callback that gets invoked when ArduinoConnection object is created (it will happen when application is started). @PreDestroy is used on disconnect method to make sure that connection to serial port is released when the program is closed.

controlTurret method is the piece of code that is responsible for sending gun turret action request to Arduino. That method is used in TurretController.executeTurretAction, remember? it uses instance of NRSerialPort to communicate over serial port (gnu.io.NRSerialPort package makes it possible). It comes form NeuronRobotics/nrjavaserial library which is a fork of RXTX that greatly simplifies serial port access. nrjavaserial takes care of loading proper native library needed to access the port (it worked well on my Windows 7 x64). As stated before, I'm not going to discuss Arduino communication and microcontroller code in this post. I will just note that you don't have to worry about casting int to byte while message array is created. It's sad but Java doesn't have unsigned bytes so it will show (byte)MESSAGE_SEPARATOR (which is 255) as -1 while debugging, but a correct value will go over wire to Arduino. Take a look at this screen shot from Free Device Monitoring Studio (you can use this tool to check what data is sent to Arduino through serial port):

Bytes sent to Arduino... Click to enlarge...

Let's get back to ArduinoConnection class: portName and baudRate properties are marked with @Value annotations. This way it is very easy to take the settings from configuration file. All you have to do is to create a file named application.properties in /src/main/resources directory and values will be automatically loaded from config. Here's the content of application.properties file: 

server.address = 192.168.0.17
server.port = 8090

arduinoPortName = COM3
arduinoBaudRate = 9600

Apart from aforementioned settings for Arduino, there are two other elements, namely: sever.address and server.port. By default Spring Boot runs the application on localhost:8080. I've changed this to custom settings to make it easy to access the application from devices connected to my WiFi network... Accessing TurretController from such devices is the reason why I added following CorsFilter class to the project:

package springarduino;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CorsFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}
}

Thanks to this Cross-Origin Resource Sharing filter it's easy to make ajax calls to executeTurretAction method without using some trickery like JSONP to circumvent same-origin policy restrictions.

And that's it! All interesting elements of the Java web app were discussed. Full code is accessible on GitHub. Since this is Gradle based project, running it is as easy as typing gradlew run. I've included Gradle Wrapper in the repo so you don't even need to have Gradle installed...