Computers


Climate control with ESPHome and Home Assistant

Two years ago I started to need controlling my home heating system while I’m not at home. I could go the easy way and buy a couple Nest thermostats, but I preferred the DIY way.

Connecting the boiler to the ESP32 via the relay module

ESP32 board with ESPHome

I connected the boiler to a ESP-WROOM-32 board via a relay module. The box and the cables were more expensive than the board (~10 EUR) and the relay module (~5 EUR).

The ESP32 board is running ESPHome: https://esphome.io/. I think it is a very nice project and very easy to setup. All the configuration is done via YAML files. The board is connected to the home WiFi and it has a fallback hotspot.

My home heating system has two radiating floor zones with two independent pumps. I also decided to automate the boiler’s “Winter mode”, in this mode the boiler heats the water for the heating, and I wanted to disable it when the heating is not working.

ESPHome has a nice web UI

In my case I needed to activate the winter mode when any pump is working and keep it working for a period of time after the pump is off.

This is my ESPHome YAML config:

substitutions:
  devicename: heating
  friendly_name: Heating

esphome:
  name: ${devicename}
  friendly_name: ${friendly_name}
  platform: ESP32
  board: nodemcu-32s

logger:

api:
  password: ""

ota:
  platform: esphome
  password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 90s

  ap:
    ssid: ${friendly_name} Fallback Hotspot
    password: !secret wifi_password

captive_portal:

web_server:
  port: 80

debug:

time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  - platform: uptime
    name: Uptime
    filters:
      - lambda: return x / 60.0;
    unit_of_measurement: minutes

  - platform: wifi_signal
    name: Wifi Signal
    update_interval: 60s

script:
  - id: keep_winter_mode_on
    mode: restart
    then:
      - logger.log: "Keep Winter mode start"
      - if:
          condition:
            and:
              - switch.is_off: zone1_pump
              - switch.is_off: zone2_pump
          then:
            - logger.log: "Keep Winter mode will stop"
            - delay: 15min
            - switch.turn_off: winter_mode
            - logger.log: "Keep Winter mode stopped"

  - id: zone1_pump_security
    mode: restart
    then:
      - logger.log: "Zone 1 security start"
      - delay: 60min
      - switch.turn_off: zone1_pump
      - logger.log: "Zone 1 security stop"

  - id: zone2_pump_security
    mode: restart
    then:
      - logger.log: "Zone 2 security start"
      - delay: 60min
      - switch.turn_off: zone2_pump
      - logger.log: "Zone 2 security stop"

switch:
  - platform: gpio
    pin: GPIO16
    name: "Winter mode"
    id: winter_mode
    inverted: true
    restore_mode: ALWAYS_OFF

  - platform: gpio
    pin: GPIO17
    name: "Zone 1 pump"
    id: zone1_pump
    inverted: true
    restore_mode: ALWAYS_OFF
    on_turn_on:
      then:
        - script.stop: keep_winter_mode_on
        - switch.turn_on: winter_mode
        - script.execute: zone1_pump_security
    on_turn_off:
      then:
        - script.stop: zone1_pump_security
        - script.execute: keep_winter_mode_on

  - platform: gpio
    pin: GPIO18
    name: "Zone 2 pump"
    id: zone2_pump
    inverted: true
    restore_mode: ALWAYS_OFF
    on_turn_on:
      then:
        - script.stop: keep_winter_mode_on
        - switch.turn_on: winter_mode
        - script.execute: zone2_pump_security
    on_turn_off:
      then:
        - script.stop: zone2_pump_security
        - script.execute: keep_winter_mode_on

Thermometers

To measure the temperature in the rooms, I used two Xiaomi Mi Home Bluetooth Thermometer 2 (~6 EUR each). They transmit the temperature via BLE (Bluetooth Low Energy) beacons.

Their LCD display is very convenient and, as they are battery powered, you can place them in the better part of the room. I flashed them with this custom firmware:

https://github.com/pvvx/ATC_MiThermometer

I’m still surprised by these small beasts, there are now firmwares to transform them in Zigbee:

https://devbis.github.io/telink-zigbee/.

Home Assistant

The control, reading the thermometers and activating the pumps, is done via a Home Assistant (HA) running in an old X86 tablet with Ubuntu (this is usually run in a Raspberry Pi or similar…).

I installed HA in a Docker container, this is my script to update and start the container:

#!/bin/bash
cd $(dirname $(readlink -f $0))
docker stop homeassistant
docker rm homeassistant
docker pull ghcr.io/home-assistant/home-assistant:stable
docker run -d \
	--name homeassistant \
	--privileged \
	--restart=unless-stopped \
	-e TZ=Europe/Madrid \
	-v ./config:/config \
	-v /etc/letsencrypt:/etc/letsencrypt \
	--network=host \
	ghcr.io/home-assistant/home-assistant:stable
docker image prune --all

Home assistant reads the thermometers via the Passive BLE monitor integration: https://github.com/custom-components/ble_monitor that can be easily installed via HACS (the Home Assistant Community Store). I needed a Bluetooth 5 USB adapter.

Then, I needed to setup two thermostats in HA via the config/configuration.yaml file:

climate:
  - platform: generic_thermostat
    name: "Living Room"
    unique_id: zone_1_thermostat
    heater: switch.zone_1_pump
    target_sensor: sensor.ble_temperature_living_room_thermometer
    min_temp: 15
    max_temp: 20
    ac_mode: false
    target_temp: 17
    cold_tolerance: 0.5
    hot_tolerance: 0
    min_cycle_duration:
      minutes: 30
    keep_alive:
      minutes: 5
    initial_hvac_mode: "off"
    away_temp: 15
    precision: 0.1

  - platform: generic_thermostat
    name: "Bedrooms"
    unique_id: zone_2_thermostat
    heater: switch.zone_2_pump
    target_sensor: sensor.ble_temperature_bedrooms_thermometer
    min_temp: 15
    max_temp: 20
    ac_mode: false
    target_temp: 17
    cold_tolerance: 0.5
    hot_tolerance: 0
    min_cycle_duration:
      minutes: 3
    keep_alive:
      minutes: 5
    initial_hvac_mode: "off"
    away_temp: 15
    precision: 0.1

Home Assistant doubles as temperature and humidity logger, and its easy to configure dashboards:

And, of course, now I’m using HA to control many other things at home.

Another complex parts were:

  • Making HA accessible via internet setting up a couple port redirections (one for HA and another for certbot) and a dynamic DNS service
  • Setup nginx and certbot for HTTPS
  • Connecting it to Google Home to allow receiving voice commands from my Nest Minis

But that is another long story…

The final installation if the ESP board, the relay module and the power adapter inside a box

Apple Vision Pro and why it is going to fail

After the initial hype (with Apple showing some nice fake videos…), it seems that now things are much more quiet about the Vision Pro. I’m sure they are going to fail, like all the previous attemps on VR “failed”, or at least they failed as a mass consumer product.

People do not want immersive experiences, or they do not want these experiences all the time. Books like “Neuromancer” or “Ready Player One” portray a society were all the computers use VR interfaces, but I think that is still not possible with the technology we have in 2024. Even if it becomes possible someday, people may not embrace it.

3D interfaces in computers are not comfortable, and all attempts to develop these kinds of interfaces have failed. Humans have been using paper, a “2D” medium, for thousands of years; that is why it’s so easy for us to interact with 2D screens on mobile phones or tablets.

We observed the evolution of past interface design trends, such as skeuomorphism, transforming into clean visual languages characterized by simplified interfaces, as exemplified by material design. The natural environment of these interfaces is 2D.

And additionally, there are other factors like the weight or the low resolution of the screens and the cameras (yes, it’s one of the biggest in the market, but it still cannot replace a real monitor, and it’s going to guarantee you dizziness when you try to read text).

There are still some niches where VR is a success, mainly those gaming related (and of course porn), but Apple is not good at any of those.

I remember some VR/AR memorable failures, the Vision Pro will soon join the list:


Slot Racing 10th anniversary

This year marks the 10th anniversary of my Slot Racing Android game. I had initially begun working on a 2.0 version, but I couldn’t find the time. A few months ago, I decided to merge the changes back into the previous app and prepare the Slot Racing 10th Anniversary edition:

In this version, I’ve removed the no-longer-functional Facebook integration and replaced it with device IDs for the leaderboard. Users can now choose any username for the times they send from their device.

One significant improvement is not immediately visible. I’ve upgraded from an old JMini3d (OpenGL 1.1) to the latest version using OpenGL 2.0. This enables the use of bitmap fonts allowing races with more than 5 laps (the old version only had textures for numbers 1 to 5).

Over the last 10 years, I’ve learned a lot about development. The code looked horrible for today’s standards, so I did a major code refactor. It now supports various race types, adding races against the chronometer.

A minor physics adjustment has been made to prevent users from taking very tight turns at full throttle, which has rendered all previous leaderboard times invalid. Additionally, the leaderboards now differentiate between each lane and the number of laps completed.

During last summer’s holidays, I added new circuits and seasons, including tracks from the current F1 season and Le Mans. Today, I’m applying the final touches to the Bluetooth code and I expect to release it soon.


OpenAI’s ChatGPT chatbot

OpenAI is a research institute that focuses on conducting research in the field of artificial intelligence. The organization was founded in 2015 with the goal of promoting and developing friendly AI, which refers to AI that is aligned with human values and that can be used to improve the lives of people. OpenAI conducts research in areas such as machine learning, robotics, and economics in order to advance the understanding and capabilities of AI. The organization is supported by a number of high-profile investors and has made significant contributions to the field of AI.

GPT is an acronym that stands for “Generative Pretrained Transformer.” It is a type of large language model that uses deep learning techniques to generate human-like text. It was developed by the research lab OpenAI, and is designed to be able to generate text that is indistinguishable from text written by a human. GPT models are trained on massive amounts of text data, and can generate responses to questions and prompts in a variety of languages and styles. They are often used for a wide range of applications, including language translation, text summarization, and conversation.

As a large language model trained by OpenAI, this chatbot is a type of artificial intelligence that is designed to generate natural language responses based on the input that it receives. It uses machine learning algorithms to process and analyze the input, and then generates a response based on the information that it has been trained on.

This chatbot does not have access to the internet, so it cannot browse or search for information online. Instead, it relies on the knowledge and information that it has been trained on to generate its responses. It is constantly learning and improving, so its responses may become more accurate and relevant over time.

Users can interact with this chatbot by typing in questions or statements, and the chatbot will generate a response in natural language. The specific capabilities and functionality of this chatbot will depend on its design and training.

And now the most interesting part: ALL THE ABOVE TEXT WAS GENERATED BY CHATGPT. It was done by asking it “What is OpenAI?”, “What is GPT?’ and “Tell me how this chatbot works in third person”. Surprised? Me too.

https://chat.openai.com/

Official announcement: https://openai.com/blog/chatgpt/


Fixing an old dehumidifier with Arduino

I purchased an Arduino UNO board approximately 10 years ago and conducted various experiments with it. Recently, my old Delonghi DEM 10 dehumidifier ceased to function due to a board issue, and the cost of replacing the original board was approximately 60€. Instead, I opted to replace the faulty board with the Arduino UNO and a two-relay board (designated for the compressor and fan).

BOM:

  • Arduino UNO: 20€
  • Relay board: 5€
  • 12V transformer: found at home
  • ~1€ in cables and screws
  • A resistor
  • Wood recycled from a packaging

And a new dehumidifier with the same specs costs ~150€, but I didn’t do this for the money….

I had a lot of fun coding the program to manage the sensors and the timer. I remembered how thermistors work and implemented the defrost and the overheat protection with a state machine, repurposing the leds to show the states. After stopping the compressor we need to wait ~20 seconds before starting it again (because the capacitor needs to be loaded).

This is the source code, it uses the thermistor library.:

#include "thermistor.h"

const int STATUS_IDLE    = 0;
const int STATUS_WORKING = 1;
const int STATUS_PAUSE   = 2;

const int PIN_FULL        = 6;
const int PIN_HIGRO       = 7;
const int PIN_COMP        = 8;
const int PIN_VENT        = 9;
const int PIN_THERMISTOR  = A0;
const int PIN_LED_ON      = 4;
const int PIN_LED_DEFROST = 3;
const int PIN_LED_PAUSE   = 2;


const long TIME_WAIT               = 50;
const long TIME_BEFORE_PAUSE       = 25 * 60 * 1000L;
const long TIME_PAUSE_TIMER        =  5 * 60 * 1000L;
const long TIME_PAUSE_DEFROST      = 10 * 60 * 1000L;
const long TIME_PAUSE_OVERHEAT     = 10 * 60 * 1000L;
const long TIME_PAUSE_COMP_OFF     = 30 * 1000L;

const int TEMP_DEFROST  =  30; // IN 1/10 ºC
const int TEMP_OVERHEAT = 350; // IN 1/10 ºC

int status = STATUS_PAUSE;

long workingTimer  = TIME_BEFORE_PAUSE;
long pauseTimer = TIME_PAUSE_COMP_OFF;

THERMISTOR thermistor(PIN_THERMISTOR,        
                      10000,          // Nominal resistance at 25 ºC
                      3950,           // thermistor's beta coefficient
                      10000);         // Value of the series resistor

void setup() {
  Serial.begin(9600);
  
  pinMode(PIN_FULL, INPUT_PULLUP);
  pinMode(PIN_HIGRO, INPUT_PULLUP);
  
  pinMode(PIN_COMP, OUTPUT);
  pinMode(PIN_VENT, OUTPUT);
  digitalWrite(PIN_VENT, HIGH);
  digitalWrite(PIN_COMP, HIGH);

  pinMode(PIN_LED_ON, OUTPUT);
  pinMode(PIN_LED_DEFROST, OUTPUT);
  pinMode(PIN_LED_PAUSE, OUTPUT);
  digitalWrite(PIN_LED_ON, HIGH);
  digitalWrite(PIN_LED_DEFROST, HIGH);
  digitalWrite(PIN_LED_PAUSE, HIGH);
}

void loop() {
  long t1 = millis();

  boolean full = digitalRead(PIN_FULL);
  boolean higroOff = digitalRead(PIN_HIGRO);
  uint16_t temp = thermistor.read();

  // Status changes
  switch(status) {
    case STATUS_WORKING: {
      if (full || higroOff) {
        Serial.println("Stopping...");
        status = STATUS_PAUSE;
        pauseTimer = TIME_PAUSE_COMP_OFF;

      } else if (temp < TEMP_DEFROST) {
        Serial.println("Pausing to defrost...");
        status = STATUS_PAUSE;
        pauseTimer = TIME_PAUSE_DEFROST;

      } else if (temp > TEMP_OVERHEAT) {
        Serial.println("Pausing due to overheat ...");
        status = STATUS_PAUSE;
        pauseTimer = TIME_PAUSE_OVERHEAT;

      } else if (workingTimer <= 0) {
        Serial.println("Pausing due to timer...");
        workingTimer = TIME_BEFORE_PAUSE;
        status = STATUS_PAUSE;
        pauseTimer = TIME_PAUSE_TIMER;
      }
      break;
    }

    case STATUS_IDLE: {
      if (!full && !higroOff) {
        Serial.println("Starting...");
        status = STATUS_WORKING;
      }
      break;
    }

    case STATUS_PAUSE: {
      if (pauseTimer <= 0) {
        status = STATUS_IDLE;
      }
      break;
    }
  }

  // New statuses and timer update
  switch(status) {
    case STATUS_WORKING: {
      Serial.println("Working");
      digitalWrite(PIN_VENT, LOW);
      digitalWrite(PIN_COMP, LOW);

      digitalWrite(PIN_LED_ON, LOW);
      digitalWrite(PIN_LED_DEFROST, HIGH);
      digitalWrite(PIN_LED_PAUSE, HIGH);
      break;
    }

    case STATUS_IDLE: {
      Serial.println("Idle");
      digitalWrite(PIN_VENT, HIGH);
      digitalWrite(PIN_COMP, HIGH);

      digitalWrite(PIN_LED_ON, HIGH);
      digitalWrite(PIN_LED_DEFROST, LOW);
      digitalWrite(PIN_LED_PAUSE, HIGH);
      break;
    }

    case STATUS_PAUSE: {
      Serial.println("Paused");
      digitalWrite(PIN_VENT, LOW);
      digitalWrite(PIN_COMP, HIGH);

      digitalWrite(PIN_LED_ON, HIGH);
      digitalWrite(PIN_LED_DEFROST, HIGH);
      digitalWrite(PIN_LED_PAUSE, LOW);
      break;
    }
  }

  // Pause and timer updates
  Serial.print("Temp in 1/10 ºC : ");
  Serial.println(temp);

  delay(TIME_WAIT);
  long t2 = millis();

  switch(status) {
    case STATUS_WORKING: {
      workingTimer -= t2 - t1;
      Serial.println(workingTimer);
      break;
    }

    case STATUS_PAUSE: {
      pauseTimer -= t2 - t1;
      Serial.println(pauseTimer);
      break;
    }
  }
}

And it feels like if I do not suck at electronics anymore 🙂


LaretasGeek AMA

Los compañeros de LaretasGeek (https://twitter.com/laretasgeek) están llevando a cabo una iniciativa de entrevistas en cadena “AMA” (Ask Me Anything) en la que el entrevistado de cada semana escoge a un invitado y lo entrevista la semana siguiente.

En esta cadena de entrevistas, Eloy Coto de Red Hat escogió entrevistarme a mí, y esta fue la entrevista:

https://www.youtube.com/watch?v=aJkifnWjug0

Una semana después, yo escogí entrevistar a Antón Román, CTO de Quobis, y nos quedó otra entrevista muy chula:

https://www.youtube.com/watch?v=jvFiG1ukAWc


Converting Carballo to Kotlin

Kotlin is a JVM language developed by JetBrains: http://kotlinlang.org gaining momentum among Android developers. Kotlin has interesting features like:

  • It can be compiled to bytecode compatible with Java >=6, allowing to use a lot of Java 7-8 features (lambdas…)  in Java 6 bytecode (=Android)
  • It can be transpiled to Javascript (like Java with GWT)

So I decided to migrate the Carballo Chess Engine code to Kotlin (and his name is Karballo) to make some experiments and having some “fun” :)… but it became a non-trivial task, the converted code is at: https://github.com/albertoruibal/karballo.

Converting the code

To start working with Kotlin I installed the Kotlin plugin for Android Studio (=IntelliJ) from:

File->Settings->Plugins->Install JetBrains Plugin

Once the Kotlin plugin is installed, it’s quite easy to convert java source files to Kotlin with: CTRL + SHIFT + ALT + K

Conversion problems

The Java to Kotlin code conversion does not work perfectly, the Carballo conversion arose these errors:

  • Kotlin is strong typed, you cannot compare a long against the literal ‘0’, you must use ‘0L’… I had hundreds of this comparisons
  • A Long cannot be initialized with an unsigned hex literal if the value does not fit in the signed type, it gives a “Value out of range” compilation error ,  so you cannot do:
    var variable = 0xffffffffffffffffL

    The solution is to convert the literals to a signed decimal:

    var variable = -1
  • Error “Property must be initialized or be abstract” with attributes not initialized in the constructor, solved adding the “lateinit” modifier to the declaration of the attributes (yes, Kotlin knows if you are initializing the attribute in the constructor)
  • Strange toInt() insertions:
    pieceNames.indexOf(pieceChar.toInt())

    should be:

    pieceNames.indexOf(pieceChar)
  • Variables of type Byte cannot be used as array indices, I had to manually change many vars from Byte to Int
  • Kotlin does not allow assignments in expressions, so it’s impossible to do:
    while ((node.move = node.moveIterator.next()) != Move.NONE) { 

    I manually had to change some cases to the more verbose:

    while (true) {
        node.move = node.moveIterator.next()
        if (node.move == Move.NONE) {
           break
        }
  • The binary operators do not work in multi line if they are placed at the beginning of the second line, only if they are at the end of the first, so:
    var myLong : Long = long1
        or long2

    does not compile, it must be:

    var myLong : Long = long1 or
        long2
  • It didn’t recognize some custom getters and I had to merge them manually, I like a lot how they look in Kotlin (notice the use of the special word “field” to avoid calling the getter recursively):
    var lastMoveSee: Int = SEE_NOT_CALCULATED
        get() {
            if (field == SEE_NOT_CALCULATED) {
                field = board.see(move, ai)
            }
            return field
        }
  • The conversion process got hung with two complex classes: CompleteEvaluator and ExperimentalEvaluator… I had to kill IntelliJ. I converted the CompleteEvaluator class copying to a new class small chunks of code.
  • Kotlin’s when() statement do not work like the Java’s switch->case, as it hasn’t breaks, you cannot jump from one option to the next excluding the break: the conversion duplicated a lot of the MoveIterator code and I fixed it manually.
  • Some other strange errors like wrong expressions and missing parenthesis…

Some things of Kotlin that I don’t like (yet)

Some are part of the claimed Kotlin “features”:

  • Kotlin does not has primitive types, but it seems to not affect the performance…
  • There is no ternary operator in Kotlin, it’s replaced with “if (…) … else …” expressions: This increases a lot the verbosity, al least in my code
  • Kotlin’s crusade against NullPointerExcepcions: It a type allows null, it must be explicitly indicated appending a question mark to the type:
    var myString : String? = null

    To convert a nullable var/val to a non-nullable, you should use the !! operator, this forces a NullPointerException if the value is null (and it seems that you are shouting to the IDE…):

    var myString : String? = "hello"
    var myStringNotNull : String = myString!!
  • Static fields and methods are grouped in a “Companion Object”
  • Compilation is slower than pure Java
  • Many bugs running from Android Studio non-android projects (IntelliJ worked better for me)
  • Couldn’t get the JS compilation working yet

And other things that I like

  • The full interoperability with Java
  • Type inference, normally I continue to specify the types, but in some cases it saves a bit of code
  • Data classes, they will save you hundreds of lines of boilerplate code https://kotlinlang.org/docs/reference/data-classes.html
  • Array initialization with lambdas
    nodes = Array(MAX_DEPTH, {i->Node(this, i)})
  • The singleton pattern is embedded in the language: using “object” instead “class” assumes that the class is a singleton
  • Visibility is “public” by default, with the access modifier “internal” it can be accessed only from the same module
  • Implicit getters / setters
  • No need for “new” to call constructors
  • And much more…

Performance

I’m my first tests, I’m not noticing any performance downgrade (or upgrade) over the Carballo Java version.


Improving Carballo Chess Engine the hard way

torneo_ajedrez

One year ago my Carballo Chess Engine (https://github.com/albertoruibal/carballo) was stuck: all the improvements that I was trying were not working, and I detected the main problem: I am a poor chess player so I will never be a good chess engine developer. I thought that the main chess programming skill was statistical analysis and not chess knowledge, but I was wrong.

So, I took the decision of starting to learn and play chess. I joined the local chess club Xadrez Ramiro Sabell (http://www.xadrezramirosabell.com) and I was so lucky that in this club teaches chess the International Master Yudania Hernández Estevez. It’s quite curious the amazing people that you can find in a small city like Ponteareas. I also try to help the club in the tournaments organization and with a small Mobialia sponsorship. Now I am playing the Galician Chess League (in third division) and all the tournaments that I can.

My chess level is improving fast (ok, I’m under 1600 ELO yet: http://ratings.fide.com/card.phtml?event=24597015), but the real deal is that the Carballo Chess Engine strength is improving much faster, climbing positions in the CCRL list (http://www.computerchess.org.uk/ccrl/4040/). Learning chess helps me to diagnose the flaws and to understand better what’s going on under the hood.

Finally,  playing chess also helps me to detect the chess player needs, so I realized the main missing feature from Mobialia Chess: a chess database to review historic games and to analyze your own games searching statistics for each position. This year I worked to implement this feature and starting today you can access a Beta version of the database in Mobialia Chess Web (http://chess.mobialia.com).


Benchmarking Java to native compilers

Java Duke

Java to native compilers have been around for some years, and I was curious about if one of this solutions could improve the performance of my Carballo Chess Engine.

I ran a tournament between binaries of the Carballo development version (1.5) compiled with different solutions to compare the performance. I used cutechess-cli to run a 3000 game tournament with time control 5″ + 0.1″ per move by side and with the Noomen Test Suite as the starting positions.

The compared binaries

  • The Pure Java Version: This is the carballo-1.5.jar ran with the Oracle JDK 1.8.0_73 VM under my 64bit linux (Debian Sid).
  • GCJ: The GNU’s Java compiler, incomplete and unfinished, but it works for Carballo. This binary was compiled with this script.
  • Excelsior Jet: A classic proprietary Java to native converter at http://www.excelsiorjet.com. I used Excelsior Jet 11 32bit for Linux (evaluation) to generate this binary. The 64bit version had worse results.
  • RoboVM: (https://robovm.com) A solution to run Java apps on iOS. Recently it was bought by Xamarin, and after the Microsoft acquisition of Xamarin, RoboVM was discontinued. RoboVM also has the option to compile Java apps to desktop binaries. I built this binary with the last RoboVM free version (1.8). Now RoboVM is forked in BugVM, but I was not able to build the binary with BugVM.
  • C# compiled with Mono: There is a C# version of Carballo converted with the Sharpen tool. I compiled this binary with MonoDevelop 5.10. The converted code is sub-optimal but it is a good solution if you need a native version (or if you need to integrate Java code in a C# project).

Test results

Rank Name                          ELO   Games   Score   Draws
   1 carballo-1.5-gcj               89    1200     62%     28%
   2 carballo-1.5                   37    1200     55%     27%
   3 carballo-1.5-mono              -5    1200     49%     30%
   4 carballo-1.5-jet              -33    1200     45%     28%
   5 carballo-1.5-robovm           -88    1200     38%     27%

Conclusions

The JVM performance is very good, better than almost all the Java to native solutions.

The exception is GCJ, but it’s incomplete and it will not work for all the Java apps.

I expected better results from Excelsior Jet, as some time ago Carballo Jet binaries where available an used for testing.

The C# version is a bit worse but acceptable.


Vender en Google Play desde España

Por aclamación popular os cuento los requisitos legales para vender aplicaciones en Google Play desde España. Me centraré en el caso de vender como trabajador autónomo, que es como estoy facturando en Mobialia. Puedes comprar muchas cosas en Google Play hasta video juegos en los cuales podras usar servicios de elo boost por parte de http://elitist-gaming.com.

CONSIDERACIONES SOBRE GOOGLE WALLET

En el Google Play los pagos se hacen a través de la plataforma Google Wallet. En Google Wallet no tenemos facturas, sólo tenemos las órdenes de venta, que son una especie de albaranes y los pagos mensuales que nos manda.

La entidad gestora de Google Wallet, Google Payment Limited (GPL) es una entidad intermediadora en el pago que no cuenta para nada (bueno sí, para enviarte el dinero).

ALTA EN HACIENDA

Para poder facturar hay que darse de alta en hacienda (modelo 036). Yo me puse en el epígrafe IAE 213 Ingenieros de Telecomunicación, cada caso personal tendréis que estudiarlo. En este formulario también escogí la modalidad de estimación directa simplificada.

Suele ser útil darse de alta en el registro de operadores de IVA intracomunitario, que necesitaréis si vais a emitir facturas a empresas europeas sin IVA.

ALTA EN SEGURIDAD SOCIAL

También es necesario darse da alta en la Seguridad Social como autónomo (modelo TA.0521) escogiendo una base de cotización según la que pagarás una cuota mensual.  Yo estoy pagando a la seguridad social 267,03 euros mensuales con la base de cotización mínima. Aunque tengas otro trabajo en el que ya estés cotizando a la seguridad social, este trámite es obligatorio.

Teóricamente si tu actividad no se considera “habitual” no tendrías que pagar esta cuota, y según la jurisprudencia vigente la actividad es habitual si generas más que el salario mínimo interprofesional. De todas formas podrías meterte en un lío si no la pagas…

TRÁMITES PERIÓDICOS

Al estar dado de alta con el 036, tenéis la obligación de presentar trimestralmente el formulario 303 de autoliquidación de IVA (pones facturas de compra, facturas de venta y pagas la diferencia de IVA entre las ventas y las compras. Anualmente también hay que presentar el formulario 390 (que es un resumen recapitulativo del IVA).

Si tenéis operaciones de IVA intracomunitarias (si se cobran anuncios de Admob o Adsense, por ejemplo) también hay que presentar trimestralmente el modelo 349, que es un modelo informativo en el que se detallan estas operaciones (además de ir su total reflejado en el 303).

También se está obligado a presentar trimestalmente el formulario 130 de pago fraccionado del IRPF, en el cual anticiparemos a la AEAT un 20% del beneficio trimestral para la próxima declaración de la renta.

En la declaración de la renta, en la sección de ingresos por estimación directa, pones los ingresos, gastos, pagos a la seguridad social como autónomo y pagas por los beneficios dependiendo del tramo de renta en el que estés.

IVA DE LAS VENTAS EN GOOGLE PLAY

En un post anterior comentaba los Cambios a partir del 1 de enero de 2015.

Desde 2015 es Google quien vende las apps directamente a los usuarios, y el desarrollador factura a Google, de forma similar a como se facturan las ventas en Amazon Appstore. La diferencia es que en este caso se le factura todo a Google Inc. USA. como se entiende al leer las Condiciones de Servicio de Google Play.

FACTURA DE COMPRA A GOOGLE POR LAS COMISIONES DEL 30%

Google no te manda ninguna factura, sólo tienes las órdenes de Google Wallet y los informes financieros de Google Play. Yo mensualmente introduzco una factura de compra a Google Inc USA pagándole las comisiones que me descuenta de las ventas (30%). Esta factura está exenta de IVA, y Google debería mandármela, pero como no me la manda, me la “invento”, ya que me la está cobrando implícitamente.

FACTURAS DE VENTA A ADMOB O ADSENSE

Si monetizáis aplicaciones a través de Admob o webs a través de Adsense, los ingresos se le facturan a Google Ireland, por lo que necesitaréis ser operador de IVA intracomunitario, ya que las facturas son también sin IVA, y trimestralemente tenéis que informar de estas facturas en el modelo 349.

Recordad que yo no soy un experto fiscal, simplemente os estoy contando mi experiencia, por lo que agradeceré comentarios y correcciones.