viernes, 30 de septiembre de 2016

El (caótico) orden de los parámetros en PHP

¿En qué estaban pensando los desarrolladores del lenguaje PHP cuando lo empezaron a desarrollar?

Llevo más de 15 años programando en PHP y todavía tengo que hacer un esfuerzo consciente en recordar el orden de los parámetros en todas las funciones de búsqueda diversas y variadas, porque en unas lo que buscas va delante, y en otras el primer argumento es dónde lo buscas.
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )

bool array_key_exists ( mixed $key , array $array )

mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )

string strstr ( string $haystack , mixed $needle [, bool $before_needle = false ] )

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [,int $offset = 0 ]]] )

De locos. Obsérvese preg_match y compárese con strpos, por ejemplo. La cadena sobre la que se busca en cada función es un argumento diferente. Hay que memorizar cada caso por separado, porque no hay una regla aparente.

miércoles, 27 de julio de 2016

Cómo subir un archivo de correo MBOX a Gmail

Tengo correos guardados en local desde hace varios años. Siempre que cambio de equipo tengo cuidado en copiarlos, están en su copia de seguridad, etc.

Pero al cliente de correo (suelo utilizar Thunderbird) ya no le gusta tener que manejar ficheros tan voluminosos (tengo algunos mbox de varios gigas). He optado por subirlos a Gmail.

La primera opción ha sido mapear la cuenta de Gmail en Thunderbird y copiar los mensajes desde el archivo local a las "carpetas" de Gmail, todo desde la interfaz de Thunderbird. Imposible, a veces da "timeout", otras veces el mismo proceso Thunderbird se cuelga.

He encontado la siguiente utilidad, imap_upload.py, un script en Python que hace lo que su nombre indica, subir a un servidor IMAP un fichero local de correo en formato MBOX.

El uso es trivial:
imap_upload.py --gmail --box="CarpetaRemota" FicheroMboxLocal

 

 

miércoles, 30 de marzo de 2016

Cacharreando con Arduino y MIDI

Sea una placa Arduinio, un "shield" MIDI, unos cuantos sensores piezoeléctricos y...


El código que mueve este prototipo de batería es trivial, sólo se limita a leer de las entradas analógicas, normaliza a los valores típicos del MIDI y dispara el sonido correspondiente.

Lo más complicado es equilibrar la sensibilidad de cada sensor, por ejemplo, el que dispara el "closed hi-hat" debe dar más volumen que el que dispara el "snare". También hay que intentar calibrar el rango dinámico de cada uno de los componentes de la batería.

/* Inputs mapping */
const int bass_drum_input = A0;   
const int snare_input = A1; 
const int closed_hihat_input = A2;
const int ride_input = A3;
const int crash_input = A4;

/* MIDI channel, instrument and notes */
const int channel=10;  
const int instrument=1; // Standard set
const int bass_drum_note = 36;   
const int snare_note = 38; 
const int closed_hihat_note = 42;
const int ride_note = 51;
const int crash_note = 49;
const int velocity_threshold = 10;
const int delay_between_commands = 30;
const int higher_value_from_piezo = 900;
int bass_drum_read, snare_read, closed_hihat_read, ride_read, crash_read = 0;


void setup() {
  Serial.begin(31250); //standard midi serial baud rate
  //Serial.begin(9600);          //  debug
  delay (200);
}

void loop() {

  bass_drum_read = analogRead(bass_drum_input);
  snare_read  = analogRead(snare_input);
  closed_hihat_read = analogRead(closed_hihat_input);
  ride_read = analogRead(ride_input);
  crash_read  = analogRead(crash_input);


  bass_drum_read = map(bass_drum_read, 0, higher_value_from_piezo, 10, 60);
  snare_read = map(snare_read, 0, higher_value_from_piezo, 10, 50);
  closed_hihat_read = map(closed_hihat_read, 0, higher_value_from_piezo, 10, 127);
  ride_read = map(ride_read, 0, higher_value_from_piezo, 10, 80);
  crash_read = map(crash_read, 0, higher_value_from_piezo, 10, 60);
  
  play_note(bass_drum_note, bass_drum_read);
  play_note(snare_note, snare_read);
  play_note(closed_hihat_note, closed_hihat_read);  
  play_note(ride_note, ride_read);
  play_note(crash_note, crash_read);
  
}

void play_note(int note, int velocity) {
   if (velocity > velocity_threshold) {
      midi_com(instrument);
      delay(delay_between_commands);  
      midi_note_on(note, 127);
      delay(delay_between_commands);
      midi_note_off(note, 0);   
    } 
}

void midi_note_on(int pitch, int velocity) {
  Serial.write(0x90+channel);
  Serial.write(pitch);
  Serial.write(velocity);
}

void midi_note_off(int pitch, int velocity) {
  Serial.write(0x80+channel);
  Serial.write(pitch);
  Serial.write(velocity);
}

void midi_com(int instrument) {
  Serial.write(0xC0+channel);
  Serial.write(instrument);
}


El código para inicializar la comunicación MIDI y enviar notas está basado en el que proponen en la página del shield.

2016-03-30 22.03.53

Placa Arduino One

2016-03-30 22.04.01

Shield MIDI, esquema de conexionado: https://www.olimex.com/Products/Duino/Shields/SHIELD-MIDI/resources/SHIELD-MIDI-sch.pdf

2016-03-30 22.04.32

El shield encajado en Arduino

2016-03-30 22.56.00

Sensores conectados al shield

lunes, 12 de octubre de 2015

Desempolvando Django (4)

Hasta ahora hemos desarrollado algo muy básico: un listado de marcadores. Casi todo lo que hemos hecho ha sido definir y configurar cosas.

Veamos los siguientes pasos:

  • Cada marcador podía llevar asociada una imagen, mostrémosla en el listado

  • Debemos asociar una hoja de estilo a nuestras páginas

  • Debemos añadir alguna forma de crear nuevos marcadores y editar los existentes

  • Hay que preparar la aplicación para ser servida en un entorno "de producción", no desde el servidor de desarrollo

  • Y muchas más características y mejoras, por supuesto, pero vamos poco a poco


Mostrando la imagen en el listado


Recordemos cómo era nuestro modelo de datos (models.py):
from django.db import models

class Marcador(models.Model):
    titulo = models.CharField(max_length=200)
    url = models.CharField(max_length=500)
    descripcion = models.CharField(max_length=500)
    image = models.ImageField(upload_to='savebookmarks')

    def __str__(self):
        return self.titulo + ' (' + self.url + ')'

Al definir el atributo imagen especificamos la ruta donde se subirán las imágenes, es relativa al parámetro MEDIA_ROOT de settings.py

Si hemos creado unos cuantos objetos desde el "/admin", podremos mostrar su imagen en el listado. Para ello, en desarrollo, definiremos en settings.py una ruta más para ser servida como recurso estático. Esto "en producción" habrá que cambiarlo, pero por ahora seguimos con ello así:

En settings.py
STATIC_URL = '/static/'
MEDIA_ROOT = BASE_DIR + '/media'
STATICFILES_DIRS = (BASE_DIR + '/savebookmarks', MEDIA_ROOT)

STATIC se refiere a cómo se sirven recursos estáticos (hojas de estilo, JS, iconos, etc). MEDIA_ se refiere a cómo se sirven ficheros subidos por los usuarios. Por seguridad, en producción, separaremos totalmente ambos tipos de recursos. En desarrollo, los servimos igualmente con la app 'django.contrib.staticfiles' mediante la definición STATICFILES_DIRS.

En la template, incorporamos la imagen (marcador_list.html):
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'savebookmarks/estilo.css' %}" />

<h2>Marcadores</h2>
<ul>
    {% for m in object_list %}
        <li>
            <img src="{% static m.image %}" width="40" />
            <a target="_blank" href="{{m.url}}">{{ m.titulo }}</a>
            | (<a href="{% url "editMarcador" m.id %}">Editar</a>)
        </li>

    {% endfor %}
</ul>

<p><a href="{% url "addMarcador" %}">Añadir otro</a></p>

El tag {% static %} es atendido por la app 'django.contrib.staticfiles' y nos proporciona la URL relativa para ser servida por el servidor de desarrollo. En producción habrá que revisar esto. El resto de código lo revisaremos a continuación.

Enlazando una hoja de estilos


directorios

Como definimos en settings.py un
STATIC_URL = '/static/'

ahora podemos poner bajo esta URL nuestras hojas de estilo. El árbol de directorios del proyecto se va pareciendo a la figura.

La app 'django.contrib.staticfiles' encontrará los ficheros bajo static/ y los servirá adecuadamente.

Para enlazar estos ficheros, usamos el tag {% static %}, como se ha mostrado en la template.

En el paso a producción lo que se hace es utilizar un servidor web independiente para servir los recursos, en la documentación de Django se explica cómo hacerlo, por ahora mantenemos esta configuración en desarrollo.

Crear y editar marcadores


En este punto, utilizaremos el sistema de formularios de Django, que está muy bien pensado.