martes, 20 de noviembre de 2018

Redireccionar salida de los comandos DOS a fichero de texto. Eñes y otros caracteres.

No es que lo utilice mucho pero de, vez en cuando, utilizo alguno de los viejos comandos DOS. Últimamente he  preparado un par de trabajos en excel: 
  • En uno de ellos recojo, por un lado, todos los ficheros mp3 que tengo en mi PC para copiarlos en una tarjeta SD, siguiendo los criterios necesarios para utilizarlos con una DFPlayer mini. Utilizo excel como elemento auxiliar para preparar un ejecutable .bat que cree los directorios necesarios y que realice la copia final.
  • En el otro trabajo quiero controlar todas las fotos que tengo en mi colección de fotos.
  • Para encontrar todos los ficheros de un determinado tipo utilizo el comando Dir del viejo DOS.
  • Me interesa conocer la fecha y tamaño de los ficheros, por eso utilizo el formato largo.
  • Cuando abro una ventana con un terminal DOS y lanzo el comando Dir *.jpg /s (desde el directorio de mi colección de fotos) tanto las eñes como las vocales acentuadas salen correctamente, las eñes se ven como eñes y las vocales acentuadas como vocales acentuadas.
  • Si redirecciono la salida del comando a un fichero de texto, al editar ese fichero de texto tanto las eñes como las vocales no se ven ni como eñes ni como vocales acentuadas.
  • Desde un punto de vista funcional, como cuando preparé la copia de los distintos mp3, creando un ejecutable bat para ello, es necesario mantener fichero original sin cambiar los caracteres que sustituyen a las eñes y vocales acentuadas por otros. El fichero BAT resultante va a trabajar con el conjunto de caracteres original. Al cambiarlos se  produce  una sustitución de caracteres en el nombre del fichero que va a impedir su correcto funcionamiento .

  • Se puede preparar un fichero bat para copiar los ficheros sin problemas, aunque veamos los caracteres cambiados.
  • Si se va a trabajar con otros programas, esos caracteres cambiados si dan problemas.

Le he dado bastantes vueltas a este tema, en realidad es un mero problema de configuración, aunque esté poco claro como solucionarlo. Por tanto se trata de encontrar algo que nos permita cambiar el conjunto de caracteres al conjunto de caracteres del español.

En su momento, antes de WindowsXp, se podía programar el conjunto de caracteres en DOS con Keyb (sp para español y 850 como código). Desaparecido el comando Keyb no encuentro manera de cambiar genéricamente el conjunto de caracteres.

Trasteando, de momento he encontrado un par de soluciones que me permite ver las eñes como eñes y las vocales acentuadas como vocales acentuadas. No es la super solución que todos desearíamos, pero es una buena solución o, al menos, una solución.

Sin instalar nada nuevo en nuestro PC:




  • Parto de una colección de canciones de los años 70, con sus eñes y sus vocales acentuadas. 
  • Alguno de los nombres ya tienen en origen las eñes cambiadas por otros caracteres. Estos cambios no se solucionan con este cambio de configuración.
  • Redireccionamos la salida del comando DOS a un fichero de texto. En el ejemplo mp3_2.txt.
  • Editamos este fichero de texto. Le añadimos, como cabecera, la siguiente instrucción HTML:
<meta http-equiv="content-type" content=text/html   charset=ibm850>

  • Con esta instrucción cambiamos en conjunto de caracteres.
  • Salvamos el fichero de texto como un fichero HTM (mp3_2.htm). Lo convertimos en una página web.
  • Abrimos ese fichero (mp3_2.htm) con Internet Explorer. A mi me funciona solo si se abre con Internet Explorer, con otros navegadores no funciona. 
  • Si en otros PC la cosa se comportase como en el mío, se verían las eñes y las vocales acentuadas.
  • Con el botón derecho del ratón pulsamos sobre el texto web. Se abre un desplegable, elegimos "Ver código fuente".
  • En el código vemos eñes y vocales acentuadas. Salvamos como texto.

Instalando en nuestro PC Libre Office:
  • Pinchamos sobre la salida txt del comando DOS con el botón derecho del ratón. 
  • Seleccionamos Abrir Con->Libre office Calc.
  • En mi PC, al menos, nos presenta un formulario de importación en el que podemos seleccionar el conjunto de caracteres que vamos a utilizar.
  • Seleccionamos "Europa occidental (DOS/OS2-850/internacional)
  • Podemos aprovechar para separar los campos que nos puedan interesar, o no. Siempre se puede hacer después.
  • Salvamos el fichero como xls, html o como odt. Ni los copia pega ni los guardar como texto conservan el cambio de caracteres. No funcionan.


martes, 16 de octubre de 2018

Estadísticas a partir del track de una excursión.



He preparado este trabajo para aquellos que les gusta trastear con el GPS y que les gustaría poder hacer sus propias estadísticas de una ruta. De paso incluyo la posibilidad que tiene excel de crear nuestras propias funciones con VBasic.

  • El primer paso consiste en pasar los datos de la ruta al libro excel.
  • Hay muchas maneras de hacerlo, desde el copia pega desde BaseCamp (propiedades de la ruta) hasta salvar los datos a un fichero de texto (o un fichero csv) o, incluso, utilizar Ibpindex para obtener esos datos.
  • A partir de estos datos puedo conocer directamente los incrementos de altura y de tiempos. Incremento = "Lo que hay" - "Lo que había"
  • La distancia recorrida hay que calcularla.
  • El rumbo hay que calcularlo.
  • Los acumulados de tiempo, distancia y alturas son una suma.

¿Como paso los datos a mi libro excel?
Esta vez voy a utilizar la utilidad que tienen algunos editores de rutas, Oziexplorer, BaseCamp, MapSource y OruxMaps, entre otros, para volcar los datos, coordenadas, alturas y fechas a un fichero de texto (.txt o .csv).
  • Oziexplorer, el editor de rutas mas antiguo que conozco, tiene la posibilidad de exportar a texto con varias, y distintas, posibilidades.

  • El trabajo que he realizado lo he hecho exportando a texto (csv) un fichero GPX con BaseCamp.

  • Abro directamente con excel el fichero csv.
  •  Elimino todo aquello que no sea los puntos de la traza.
  • Desde datos->Texto en columnas paso cada item a su columna.

  • Pasados los campos a su columna copio los datos y los pego en el libro EstadísticasManuales.xls, hoja Datos.

Como mínimo, a partir de fecha, coordenadas y alturas puedo calcular:

  • Distancia entre dos puntos y distancia acumulada.
  • Tiempo entre dos puntos y duración total.
  • Incremento de altura entre dos puntos y acumulados de subida y bajada.
  • Velocidad de recorrido. Entre puntos y total.
  • Tiempo en movimiento y de parada.
  • Eliminar puntos que no cumplen o que cumplen unos determinados criterios. En el ejemplo tiempo mínimo entre puntos, distancia mínima entre puntos y velocidad máxima. Otro criterio que se puede incluir es el de velocidad vertical (de subida o bajada), etc..
  • Para calcular tiempos y, dado que depende del tiempo, velocidades, hay que tener presente el sistema de fechas de excel. 

  • Si en una celda escribimos una fecha y cambiamos el formato fecha a formato numérico vemos un número en vez de una fecha. Es el número de días trascurridos desde el 1/1/1900. Uno equivale a un día, la fracción de uno es la fracción de día. Este sistema no me acaba de gustar, es bastante imperfecto. 
  • Las velocidades, en km/hora se calculan con distanciaEnMetros/(tiempo*24000). 1000 para pasar los metros a km y 24 para pasar los días, o su fracción, a horas.
  • Las duraciones, sin embargo, se calculan restando sin mas  las fechas y sus acumulados sumando las duraciones.
  • Los incrementos de altura son sencillamente una resta. Altura del punto2 menos la altura del punto1.
  • El calculo de las distancias es lo único realmente complejo de todo esto. Hay varias posibilidades, incluida una manera aproximada de calcularla.

Distancia entre dos puntos:

Buscando en internet encontré, hace ya varios años, una fórmula que es la que utilizo desde que empecé a hacer mis propias estadísticas.


La fórmula es bastante compleja, no difícil convertirla a fórmula excel pero queda un formulón,  por lo que creo mi propia función en VBasic a partir de esa fórmula, la funcion DGeo (distancia geográfica), que es mucho mas sencilla de manejar:



Function DGeo(Lat1, Lon1, Lat2, Lon2)

Dim GaR, R, Lat1R, Lat2R, Lon1R, Lon2R
DGeo = -1
On Error Resume Next
'57.29577951 para convertir grados a radianes
'6378137 Radio de la tierra
GaR = 57.29577951
R = 6378137
Lat1R = Lat1 / GaR
Lat2R = Lat2 / GaR
Lon1R = Lon1 / GaR
Lon2R = Lon2 / GaR





'DGeo = R * Atn(Sqr((1 - (Sin(Lat1 / GaR) * Sin(Lat2 / GaR) + Cos(Lat1 / GaR) * Cos(Lat2 / GaR) * Cos(Lon2 / GaR - Lon1 / GaR)) ^ 2)) / _

(Sin(Lat1 / GaR) * Sin(Lat2 / GaR) + Cos(Lat1 / GaR) * Cos(Lat2 / GaR) * Cos(Lon2 / GaR - Lon1 / GaR)))





DGeo = R * Atn(Sqr((1 - (Sin(Lat1R) * Sin(Lat2R) + Cos(Lat1R) * Cos(Lat2R) * Cos(Lon2R - Lon1R)) ^ 2)) / _

(Sin(Lat1R) * Sin(Lat2R) + Cos(Lat1R) * Cos(Lat2R) * Cos(Lon2R - Lon1R)))





On Error GoTo 0

End Function



Esta función, mi función, la función añadida por mi, como fórmula excel queda:

=Radio* ATAN(RAIZ((1 - (SENO(D2*GaR) * SENO(D3*GaR) + COS(D2*GaR) * COS(D3*GaR) * COS(E3*GaR - E2*GaR)) ^ 2)) / (SENO(D2*GaR) * SENO(D3*GaR) + COS(D2*GaR) * COS(D3*GaR) * COS(E3*GaR - E2*GaR)))



Donde:


  • Radio=radio de la tierra. Es una variable con nombre.
  • De GaR sirve para convertir grados a radianes. Es una variable con nombre. Podía haber utilizado la función RADIANES().
  • Columna D es la latitud. 
  • Columna E es la longitud.
Entre ambas maneras de calcular distancias hay una pequeña diferencia.

Para distancias cortas he encontrado una manera aproximada de calcular la distancia entre dos puntos, columna I de la hoja "datos2". Empiricamente hay muy poca diferencia para puntos cercanos en metros y bastante diferencia para puntos muy separados. Creo que como estamos trabajando con la traza de una excursión a pie o en bici los puntos están muy cerca unos de otros podemos utilizar la siguiente fórmula:
  • =RAIZ(((D2-D3)*M_G)^2+(M_G*COS(D3*GaR)*(E2-E3))^2), que tampoco se puede considerar una formulita.
  • Columna D es la latitud. 
  • Columna E es la longitud.
  • M_G es una variable con nombre. Es el número de metros por grado en el Ecuador de la tierra.



Rumbo: El rumbo es el ángulo que forma nuestra dirección, la dirección que llevamos al movernos,  con el eje norte-sur, con una brújula graduada es fácil de ver. Es una información, también desde mi punto de vista, mas útil en náutica que sobre tierra, en tierra nuestros tramos rectos son pequeños y nuestro camino va por donde va, casi nunca podemos ni elegir el rumbo ni salirnos del camino. Hay varios casos mas en los que el ángulo entre una dirección y el eje norte-sur se puede utilizar, pero no vienen al caso.
  • No he conseguido encontrar una fórmula exacta de calcular el rumbo, pero si una fórmula aproximada para puntos cercanos.
  • Queda una fórmula compleja, por lo que ni siquiera intento pasarla a excel. Solo hago la fórmula en VBasic.
  • En tierra solo he visto utilizar el rumbo para eliminar algunos puntos. Si tres puntos consecutivos tienen el mismo rumbo se puede eliminar el punto central sin perder demasiada información.
Código de Rumbo:

Function Rumbo(Lat1, Lon1, Lat2, Lon2)
Dim D1 As Double, D2 As Double, D3 As Double, ArcoTan As Double
'corregir casos 2 y 4
'111319.491
'Pi = 3.141592654

D1 = DGeo(Lat1, Lon1, Lat2, Lon2)
D2 = DGeo(Lat1, Lon1, Lat2, Lon1)
D2 = Abs(111319.491 * (Lat2 - Lat1))
D3 = DGeo(Lat2, Lon1, Lat2, Lon2)
D3 = Abs(111319.491 * (Lon2 - Lon1) * Cos(Lat2 * 2 * Pi() / 360))
On Error Resume Next

C = 0
ArcoTan = Atn(D3 / D2)
e = Err()
If (D2 > 0 And D3 > 0) Then
If Lat2 >= Lat1 And Lon2 <= Lon1 Then
Rumbo = (2 * Pi() - ArcoTan)

End If
If Lat2 >= Lat1 And Lon2 >= Lon1 Then
Rumbo = ArcoTan

End If
If Lat2 <= Lat1 And Lon2 <= Lon1 Then
Rumbo = Pi() + ArcoTan

End If
If Lat2 <= Lat1 And Lon2 >= Lon1 Then
Rumbo = (Pi() - ArcoTan)

End If
End If

If D2 = 0 Then
Rumbo = Pi() / 2
If Lon1 > Lon2 Then Rumbo = 1.5 * Pi()
End If

If D3 = 0 Then
Rumbo = 0
If Lat1 > Lat2 Then Rumbo = Pi()
End If

On Error GoTo 0
'f = "0." & Left("0000000000000", Dec)
'Rumbo = Format(Rumbo * 360 / (2 * Pi()), f) + 0
Rumbo = Rumbo * 360 / (2 * Pi())
End Function

Function Pi()
Pi = 3.141592654

End Function

En donde Lat1,Lon1,Lat2 y Lon2 son las coordenadas del punto de inicio y del punto de destino.

viernes, 5 de octubre de 2018

Cambios de base. De decimal a binario y de decimal a hexadecimal.

Estoy trabajando, en mi blog de cacharreo, con un reproductor de mp3, el DFPlayer Mini y un Arduino Uno. El aparato se puede programar directamente, según la documentación del fabricante, o se puede programar siguiendo alguna de las librerías preparadas al efecto. La muy escasa documentación del fabricante sobre este aparato hace referencia a unos comandos escritos directamente en hexadecimal, aunque en la práctica ese hexadecimal se convierte en una base de ocho bits, los ocho bits de un carácter ascii.
Como apoyo a lo que estoy haciendo, por un lado hablar el mismo idioma (hexadecimal) del pdf del fabricante y por otro trabajar, de hecho, con una base de 8 bits, he preparado un libro excel que me permite estar seguro, antes de entrar en la programación del Arduino, de lo que estoy haciendo.





  • La primera conversión, líneas 6 y 7 es la de decimal a binario. En este caso no la utilizo para nada, pero es la base de la electrónica digital.
  • Hago una conversión de decimal a hexadecimal en las líneas 21 y 22.
  • Hago una conversión de decimal a una base byte, una de dos caracteres u una de cuatro caracteres.
  • Por último hago una conversión de decimal a decimal, como comprobación de la idea.
  • Normalmente, en nuestro sistema de numeración, el número de menor peso es el de más a derecha y el de mas peso es el de mas a la izquierda.
  • Independientemente de la base de numeración, cada una de las unidades  de una cifra vale el número de valores que toma la base de numeración elevado a un exponente, cero el de mas a derecha, uno el siguiente, dos, tres y así sucesivamente.
  • Esto es fácil de seguir, partiendo de cero, sumando sucesivamente uno, en binario pasamos de cero a uno y de uno a 10. En decimal pasamos de 9 a 10. En hexadecimal pasamos de 0F a a 10.
  • Para pasar de una cifra a otra debemos incrementar n (número base, contando el cero) veces la cifra de la derecha.
  • Si continuamos el razonamiento, para llegar a la tercera cifra hemos tenido que incrementar n^2 veces el cero inicial. En decimal 100, tres cifras, es 99 +1, es 10^2 cada unidad de esa tercera cifra vale 10^2. Lo mismo para 1000, cuatro cifras, 999+1, cada unidad de esa cifra vale 10^3.
  • Este razonamiento es válido para el resto de las posibles bases de numeración que se nos ocurra.
  • En la conversión de decimal a otra base hay que introducir el concepto resto. Vamos a calcular la cifra N (empezando en cero). Debemos quitar el valor de las cifras de mas a la izquierda, a partir de N+1, esto se hace hallando el resto de dividir el valor decimal por la base elevada a N+1.
  • El entero de dividir ese resto por la base elevada a N nos da el valor de esa cifra.
  • Repitiendo ese proceso hallamos todas las cifras de la conversión.
Esto, quizás parezca un poco lioso, pero el la práctica resulta sencillo.



martes, 7 de agosto de 2018

Copia y renombre masivo de ficheros con apoyo en Excel. Preliminar.

Una noche de insomnio compre en amazón un lector mp3 para Arduino, con el fin de incorporar música a alguno de mis proyectos. Como lo compré sin meditarlo mucho, al empezar, al intentar utilizarlo, me di cuenta de que no era exactamente lo que yo pensaba que era, no se ajustaba exactamente a lo imaginado. Lleva un soporte de tarjeta microsd en donde se supone que tenemos que tener la música.
En concreto los diferentes mp3 ni pueden llamarse de cualquier manera, ni pueden estar donde me apetezca, deben tener como nombre un número y estar en la raíz de la tarjeta microsd.
¿Como hago yo una copia masiva de mis mp3 y, además les pongo otro nombre?:Con el antiguo DOS y con apoyo en Excel.



  • En windows, abriendo un terminal DOS (con CMD en la línea ejecutar) o bien creando un fichero ejecutable .bat
  • Utilizo el comando dir c:\*.mp3 /s /b >mp3.txt
  • Este comando da todos los mp3 que hay en el disco C: y redirecciona la salida a un fichero de texto (mp3.txt)
  • Por supuesto que no es necesario buscar en todo el disco, podemos buscar en varios directorios de uno en uno. Solo hay que incorporar una línea por directorio y redireccionar la salida como >>mp3.txt
  • En mi PC algunos caracteres no se representan correctamente. No importa, al utilizarlos de vuelta, se compensa ese error.
  • Este error parece que se soluciona configurando el DOS a teclado en español (keyb sp o kb16 sp dependiendo del tipo de windows), pero en mi windows no están instalados ninguno de ellos.
  • Con cualquier editor de texto, o abriendo el fichero de texto directamente desde excel, copiamos el contenido de este fichero en una hoja excel (a1)
  • Vamos a preparar un fichero ejecutable .bat de DOS.  En las columnas B y C preparo el ordinal, el nombre de la copia. En B incremento el ordinal (B2=B1+1) y en C pongo los ceros a la izquierda necesarios, con =DERECHA(100000+B1;5).
  • En la columna D preparamos una línea con el comando de DOS copy. El nombre original va precedido y seguido de comillas, de esa manera podemos incluir espacios en blanco en los nombres.
  • El nombre de destino, en este caso, no tiene espacios en blanco, luego no necesitamos incluir las comillas.
  • El comando resultante, uno por línea, es:="copy " & CARACTER(34) & A1 & CARACTER(34) & " c:\temp\mp3\" &C1 & ".mp3".
  • Copiamos toda la columna en un fichero .bat, ejecutable en DOS. Salvamos.
  • Ejecutamos el .bat, podemos o no desviar la salida a un fichero de texto, lo que nos permite controlar los posibles errores de copia. Nos copia todos los ficheros mp3 en un solo directorio y con los nombres adecuados.
  • Ya solo nos queda pasarlos, si no lo hemos hecho directamente, a la tarjeta SD.
Ayer por la mañana escribí la primera parte de este articulo. Por la tarde me estuve documentando sobre el lector de mp3 y parece que si admite que la tarjeta SD tenga directorios aunque con algunas limitaciones.
Preparo una segunda  hoja (hoja2), en el libro CopiarMp3_2.xls, que me separa los mp3 por directorios. En principio tanto las canciones como los directorios toman un nombre numérico, que es lo que recomiendan algunas páginas.
  • Para separar los directorios necesito conocer la última posición del carácter "\". Para ello creo una función, Ultima,  en vbasic para encontrar esa ultima posición.
  • Una vez separado el directorio , con =SI($B4<>$B3;$D3+1;$D3) incrementamos el número de directorio. Esta instrucción se puede leer como "si el directorio actual es distinto del directorio anterior, incrementa uno. Si no déjalo como está"
  • Para numerar las canciones dentro de su directorio utilizo =SI($B4<>$B3;1;$H3+1), que puede leerse como "si el directorio anterior es distinto del actual pon 1, si no incrementa uno".
  • En la columna F preparo unas instrucciones DOS, con = " mkdir " & $H$1  & DERECHA($D3+1000;3), para crear los directorios mediante un fichero ejecutable ".bat". Estas instrucciones se copian en un fichero .bat, que debe ejecutarse antes de la copia de los mp3.
  • Dejo abierta la posibilidad de trabajar con los nombres de directorios o/y ficheros.
Mi propia función, la función Ultima(): Entrando en los módulos VBasic podemos verla. No tiene gran explicación, se basa en la instrucción vbasic InStrRev que nos da la última aparición de un determinado carácter en una cadena alfanumérica


Function Ultima(Cad, Sep)

'Cad=Cadena alfanumérica

'Sep=separador, carácter buscado.

Ultima = InStrRev(Cad, Sep)


End Function

La pregunta es ,Y dado que nos metemos a programar en vbasic ¿porque no lo hacemos todo de una tacada en vbasic?
Código de la función que lee el fichero con los mp3 y crea un ejecutable (.bat). Este ejecutable crea los directorios y copia los ficheros.
Aunque también escribe en el excel, este paso no es necesario. Se puede omitir.
Cuando utilizo un fichero de texto creado con windows 7 me aparecen una serie de caracteres (unicode) que me introducen unos salto de línea incontrolados, que se pueden eliminar copiando a excel la línea para después recuperarlos.

Código de la función:
Sub Proceso()
Dim Carac, Lin, DirT, Datos, Salida, N, Pos1, Pos2, LinA, C(255)
Dim Lat, Lon, V, FH, Fic, Dir2, Dir1, DirAnt, ND, NF
'DirEntr = "C:\Documents and Settings\Fernando y Use\Mis documentos\Mi Garmin\"
'Nom = "fUENCARRAL, tRES cANTOS, aLCOBENDASReal.gpx"
With Sheets("Config")
DirT = .Range("b1").Value
Datos = .Range("b3").Value
Salida = .Range("b2").Value
End With
'Sheets(1).Range("a" & 1 + NF) = DirEntr & Nom
Close #1
Close #2
Open Datos For Input As #1
Open Salida For Output As #2


Lin = ""
N = 1
With Sheets("Datos")
.Select
.Cells.Clear
'MsgBox DirEntr & Nom
Do While Not EOF(1)

Carac = Input(1, #1)
C(Asc(Carac)) = C(Asc(Carac)) + 1
'If Asc(Carac) = 127 Or Asc(Carac) = 129 Or Asc(Carac) = 141 Or Asc(Carac) = 143 Or Asc(Carac) = 144 Or Asc(Carac) = 157 Then MsgBox Asc(Carac)

If (Asc(Carac) = 10 Or Asc(Carac) = 13) And Lin <> "" Then
N = N + 1


Pos1 = Ultima(Lin, "\")
Fic = Mid(Lin, Pos1 + 1)
Dir1 = Left(Lin, Pos1 - 1)
Pos1 = Ultima(Dir1, "\")
Dir2 = Mid(Dir1, Pos1 + 1)
If DirAnt <> Dir2 Then

ND = ND + 1
.Range("f" & ND + 1) = " mkdir " & DirT & Mid(1000 + ND, 2)
'.Range("g" & ND + 1) = " mkdir " & DirT & Dir2
Print #2, " mkdir " & DirT & Mid(1000 + ND, 2)
NF = 1
End If

Sheets("config").Range("d1").Value = Lin
' en Sheets("config").Range("e1")  hay que colocar la fórmula =limpiar(D1)
Lin = Sheets("config").Range("e1").Value
.Range("a" & N) = Lin
.Range("b" & N) = Dir1
.Range("c" & N) = Dir2
.Range("d" & N) = ND
.Range("e" & N) = Fic
DirAnt = Dir2
Print #2, " copy " & Chr(34) & Lin & Chr(34) & " " & DirT & Mid(1000 + ND, 2) & "\" & Mid(1000 + NF, 2) & ".mp3"
Lin = ""
NF = NF + 1
Else

If Asc(Carac) <> 13 And Asc(Carac) <> 10 Then Lin = Lin & Carac

End If
Loop

'.Range("1") = N
For i = 0 To 255
.Range("h" & i + 2) = i
.Range("i" & i + 2) = C(i)
.Range("j" & i + 2) = Chr(i)
Next
End With


Close #1
Close #2

End Sub


Caracteres no imprimibles: En principio son aquellos cuyo código ascii es menor de 32 (espacio). los no imprimibles van de de 0 a 31. En texto unicode hay otros  caracteres no imprimibles (127,129,141,143,144 y 157).


martes, 10 de julio de 2018

Bascula de cocina con un FSR y un Arduino Uno. Estudio preliminar con excel.

Estoy preparando una bascula de cocina con un FSR, un sensor de peso, y un Arduino Uno, en una articulo anterior analizo un poco la gráfica del fabricante del sensor de peso. Esta vez, ayudándome, como la vez anterior, de un libro excel, analizo el posible comportamiento del proyecto.
  • Utilizo un divisor de tensión, una resistencia fija y el propio FSR. En este caso R2 en la resistencia fija y el FSR es R1.
  • La salida Vout se lleva a un convertidor A/D, lo que nos da un valor digital que a su vez, nos permite conocer el valor que tiene el FSR en ese momento y dado ese valor, conocer el peso que hay sobre el.

  • La conversión A/D da una serie limitada de valores, hay un salto conocido entre cada dos valores de tensión.
  • La gráfica del fabricante es logarítmica, el FSR tiene un comportamiento logarítmico, lo que supone que un mismo salto de tensión entre dos medidas en el convertidor A/D, no se corresponda con los mismos gramos de diferencia. Según aumenta el peso, el incremento de peso para un mismo salto  entre dos medidas, es mayor. 
  • Se supone, según la gráfica del fabricante, que el FSR puede pesar hasta 10kg. Como creo que es bastante difícil construir un platillo de báscula con menos de 50 gramos, el comienzo del tercer tramo lineal de la gráfica, solo considero en el libro excel ese tercer tramo.
  • El libro excel incluye la gráfica del fabricante (GResistenciaGramos) y los cálculos necesarios para conocer para conocer la pendiente del tramo lineal. (hoja Tramo3)
  • Sobre la gráfica del fabricante aparecen los valores calculados, tanto de la hoja Tramo3 como para la hoja GResistenciaGramos. 



Creando la gráfica XY

Valores de la Gráfica del fabricante.


Valor de los ejes y escala logarítmica.

Gráfica del fabricante como fondo de nuestra gráfica XY

  • La hoja GResistenciaGramos permite conocer, de momento de un modo preliminar, el comportamiento del proyecto.
  • Número de bits del convertidor A/D, en la celda A2. En esta celda se puede escribir lo que se quiera, aunque como es lógico, se debe incluir un valor que se corresponda con un valor de un convertidor A/D comercial.
  • El propio Arduino Uno incluye un convertidor A/D de 10 bits. En internet he encontrado convertidores externos al arduino de 12, 14 y 16 bits. 
  • Un mayor número de bits aumenta la precisión y un menor número de bits la disminuye. Con 10 bits, al aproximarnos al peso máximo, 10kg., cometemos un error de cuantificación de casi medio kilo. Con 14 bits pasa a ser de poco mas de 30 gr.
  • La hoja GResistenciaGramos está preparada para funcionar completamente con un convertidor de hasta14 bits. Con 16 bits funciona parcialmente, habría que expandir las formulas mas alla de la línea 65000.
  • Los cálculos están realizados con los valores digitales de tensión, tanto en su valor máximo como en los posibles valores intermedios.
  • La resistencia R2 se calcula en función, tanto del número de bits del convertidor como del primer valor que queremos que tengo nuestro proyecto así como del inicio del tramo que estemos considerando. En este caso parto, según la gráfica del fabricante, para 50 gramos, de 10000 ohmios.
  • En la celda B7 podemos variar el valor digital que queramos para esos 50 gr.
  • En C2 se calcula el valor teórico de R2. Entre D2 y D5 se aproxima, con hasta tres resistencias, puestas en serie, un valor comercial a ese valor teórico.
  • En H2 podemos indicar cual es el valor optimo de nuestra bascula. Aunque podamos pesar hasta 10kg, nuestro valor optimo puede ser mucho menor.
  • Da el primer peso superior a nuestro peso optimo, la línea en que aparece y el posible error que se puede producir, que se corresponde con el último salto entre pesos, y que también se corresponde con el máximo error que consideremos bueno para nuestro proyecto.
Gestión de errores:

La hoja GResistenciaGramos tiene un gran número de líneas con unas fórmulas que algún momento, según los valores correspondientes, producen un error. Estos errores se pueden gestionar de muchas maneras, pero creo que hay que gestionarlos, queda mucho mejor y evita otros errores en cadena, aunque ello suponga un incremento del peso de las fórmulas.
  • En la columna C controlo el posible cero o menor que cero cambiando el valor por el último valor superior a cero con =SI($C$2*(Vmax-$B12)/PV>0;$C$2*(Vmax-$B12)/PV;$C11)
  • En la columna E ese control de error lo hago con SI.ERROR(10^((LOG10(D8)-Cte)/Pend);$E7), aunque  este caso es un caso de error en cadena. Se produce cuando D8 (C8/1000) toma un valor negativo. Al haber resuelto el error, valor de C8 menor que cero, en esta columna no deberían producirse errores.


lunes, 2 de julio de 2018

Comprendiendo el gráfico de un sensor FSR. Preliminar a una bascula de cocina con Arduino Uno.

Sigo falto de ideas. Esta vez pienso en hacer una bascula de cocina con un Arduino Uno y un sensor de peso FSR. Aunque este tipo de sensores parece que no permiten medidas muy precisas, para una báscula de cocina probablemente valgan.
Documentarse, a veces, no es fácil, aunque en internet haya cientos de páginas de casi todo.
Un sensor FSR es un sensor de peso, es una resistencia variable que varía su valor en función del peso que esté sobre el. La gráfica fuerza/resistencia que he encontrado en internet para un FSR es la siguiente:



Con este tipo de gráficos el fabricante pretente explicar como se comporta su producto. Por otra parte, la pregunta es ¿Como llevo yo los valores  de la gráfica a mi proyecto? de alguna manera debo llevar a gráfica al proyecto.

Puede verse que el eje X está etiquetado en gramos y el eje Y lo está en ohmios.

  • En las hojas de características del sensor dice que es un gráfico "logaritmico".
  • Vemos que eje X presenta tres divisiones, del mismo tamaño, y cuatro etiquetas 10, 100, 1000 y 10000.
  • Estas divisiones necesariamente se corresponden con logaritmo (base 10) de lo etiquetado, logaritmo de 10 es uno, de cien es dos, de mil es tres y de diez mil 4.
  • Lo mismo pasa con el eje Y, divisiones con el mismo tamaño y etiquetas que no se corresponden con esas separaciones. 
  • Logaritmo de 0,1 es -1, de 1 es cero, de 10 es uno y de 100 es 2.
Vemos que  gráfica presenta tres tramos aparentemente lineales, tres tramos que se pueden asimilar a una linea recta (y=mx+c) 
  • El primer tramo (de izquierda a derecha) va desde 10 a 20 gr. (aprox.)
  • El segundo tramo va de 20 a 50. (aprox)
  • El tercer tramo va de 50gr. a 10 kgr.
Si vamos a construir una báscula de cocina es muy probable que solo el platillo de la báscula pese mas de 50 gramos, con lo que el peso que habrá sobre el sensor siempre estará por encima de esos 50 gramos que marcan los dos primeros tramos. Podemos no considerar, prescindir, al codificar el programa, de los dos primeros tramos, aunque incluirlos en nuestro código tampoco va a pesar mucho.

Incluyo la gráfica del FSR como fondo en una gráfica XY de excel:
  • Con los puntos resaltados en la propia gráfica del FSR compruebo (a ojo) lo que había supuesto, la presencia de tres  (o mas) tramos lineales.
  • Los dos primeros están claramente diferenciados, el tercero aunque también parece que se puede aproximar a  un solo tramo, tampoco pasaría nada si lo dividiésemos, a su vez, en varios tramos.
  • Me centro en el tercer tramo, sobre el que en un trabajo real trabajaremos. Con los valores obtenidos calculo los parámetros de la línea  (y=mx+c)  con la que vamos a trabajar.
  • Recordemos que nuestra gráfica del FSR es logarítmica, tanto los valores de X como los de Y son el logaritmo de X o de Y (log(y)=m.log(x)+c) 
  • Estos calculos están en la hoja Tramo3.
  • Incluyo en la gráfica GLog esos datos. Veo que la línea se sitúa sobre la imagen de fondo.

Con un Arduino podemos encontrar la respuesta del FSR ante un peso. Basta con hacer un divisor de tensión con una resistencia fija y conocida, la segunda resistencia sería el propio FSR, medir la tensión de salida y realizando el calculo adecuado encontraremos el valor de la segunda resistencia.


Con ese valor, Vout, calculamos la resistencia incógnita. Como estoy en los preliminares todavía no he decidido si el FSR va a ser R1 o va a ser R2, ni el valor de la resistencia fija que lo acompañara. Si fijamos R2, despejando, (R1=R2(Vin-Vout)/Vout) 
Con este valor entramos en  (log(y)=m.log(x)+c). En este caso Y=R1, despejamos log(X), hayamos el antilogaritmo y ya tenemos nuestro peso encontrado.

sábado, 24 de marzo de 2018

Cálculo del condensador de una fuente de corriente continua.



Este trabajo permite calcular el condensador de una fuente de corriente continua conocidas su tensión nominal y su consumo, en amperios, máximo. El resultado es en microfaradios.

Variables con nombre utilizadas:
  • Amp (=Condensador!$D$5) Consumo, en amperios.
  • CarQ1 (=Condensador!$D$7) Carga del condensador cuando la tensión es la tensión máxima.
  • CS (=Condensador!$E$5) Ciclos por segundo.
  • Descarga (=Condensador!$C$7) Perdida de carga entre Vmax y Vmin.
  • Periodo (=1000/CS) Tiempo de un ciclo de C.A.
  • TDesc (=Condensador!$B$7) Tiempo total de descarga.
  • Vmax (=Condensador!$C$3) Tensión máxima.
  • Vmin (=Condensador!$D$3) Tensión mínima.
  • Vn (=Condensador!$B$3) Tensión nominal.
Partimos de la tensión nominal de la fuente de C.C. y el consumo para la que estamos calculando el condensador.

  • Utilizamos una fuente con un trasformador del mismo valor nominal que la salida de C.C.
  • La señal a la salida del trasformador llega hasta ese valor nominal multiplicado por raíz de dos.
  • La tensión en bornes del condensador debe estar siempre por encima del valor nominal. En este caso he supuesto un margen de 1,5 voltios.
  • Supongo una descarga lineal del condensador. Estamos trabajando en un tramo casi lineal de la descarga.
  • El usuario solo debe indicar la tensión nominal, casilla B3 y el amperaje, casilla D5.
  • El resto de la hoja debería estar protegido, no lo está, lo dejo desprotegido para que cada cual pueda adaptarla a su gusto.
Cálculo matemático:
  • El condensador tiene una capacidad fija, no varía.
  • C=Q/V. Tenemos dos tensiones, la máxima y la mínima.
  • Esto supone que cuando el condensador está a la tensión máxima tiene una carga y cuando esta a la tensión mínima, tiene otra carga.
  • La diferencia entre ambas cargas la da el consumo, en amperios, por el tiempo de descarga.
  • El tiempo de descarga va desde el momento en que la señal alterna llega a su valor máximo y (1/4 del periodo), baja a cero y el momento en que la señal vuelve a alcanzar el valor mínimo deseado.
  • Vmin=Vmax*sen(a). Despejamos y calculamos el arco seno de a
  • Repartimos el periodo en proporcionalmente ese arco seno.
  • Td=Periodo*ArcoSeno/(2*pi)+1/4 Periodo.
  • Q1/V1=Q2/V2==>Q1/V1=(Q1-I*T)/V2.
  • Despejando Q1=I*T/(1-V2/V1)


martes, 2 de enero de 2018

Automatización de tareas con Excel. Manejo Power Point desde Excel con VBasic.Preliminar

En el artículo anterior hice una especie de gestor de fotos con excel. De momento sigue estando en fase preliminar pero cuando este terminado tendré que dotarlo de una manera sencilla de, además de tener una relación de fotos, un elemento que me permita ver las fotos seleccionadas. En la versión preliminar el libro excel  da un código html que hay que llevar a un fichero de texto (html), ejecutarlo y, con un poco de suerte, ver las fotos. Una de las posibilidades que permiten ver las fotos seleccionadas es incluirlas automáticamente en una presentación  Power Point, desde el gestor de fotos excel.

Trabajos preliminares, para empezar a usar códigos un poco, no mucho, mas complejos.

En Power point:
  • Por un lado, necesitamos saber el código vbasic de Power Point que nos permita incluir, en este caso fotos, objetos en una presentación.
  • Abro una presentación, busco la grabadora de macros, la activo, realizo manualmente la tarea deseada.
  • Añado una diapositiva. Añado una foto. Añado un cuadro de texto. 
  • Detenemos la grabación de la macro. Vemos el código escrito por la grabadora de macros. 
  • Hemos obtenido un código que nos facilitará en trabajo de escribir nuestro código.
En Excel:
  • Para manejar PP desde el vbasic de excel necesitamos incluir la librería correspondiente.
  • Abrimos el libro excel correspondiente y con Alt+F11 vamos a los módulos vbasic.
  • Con el menú Herramientas->Referencias busco y añado esa librería, en este caso "Microsoft Power Point 15.0 Object Library".
  • En uno de los módulos creamos una macro que incluya nuestro código.
  • En esa macro incluimos el objeto Power Point con Set ApliPP = New PowerPoint.Application.
  • Añadimos una presentación con Set PresenPP = ApliPP.Presentations.Add
  • Buscamos en la macro grabada por la grabadora de macros la manera de añadir una hoja. La adaptamos a nuestro código, y queda .Slides.Add(Index:=I, Layout:=ppLayoutBlank).Select
  • Buscamos, en la macro grabada, como añadir una imagen a la hoja.
  • Adaptamos esa instrucción a nuestro código. La instrucción resultante es 
  • ApliPP.ActiveWindow.Selection.SlideRange.Shapes.AddPicture(FileName:=Nom, LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, Left:=40, Top:=30, Width:=640, Height:=480).Select
Con el siguiente código vbasic podemos importar todas las fotos de un directorio de nuestro PC a una presentación PowerPoint desde nuestro libro Excel.


Sub PresPower()
Dim ApliPP As PowerPoint.Application
Dim PresenPP As PowerPoint.Presentation
Dim Diapo As PowerPoint.Slide
Dim Hoja
Dim Nom As String
Dim H

Set ApliPP = New PowerPoint.Application

ApliPP.Visible = True
ApliPP.Activate
Set PresenPP = ApliPP.Presentations.Add

With PresenPP
'*********** Esta parte no es necesaria, la arrastro de otra versión 
'*********** Elimina todas las diapos. de una presentación
For Each Hoja In .Slides
Hoja.Delete
Next
'**********************
I = 1
x = Dir("C:\DiscoWindowsXP\Fotos\20131010Duraton\*.JPG")


  While x <> ""
  Nom = "C:\DiscoWindowsXP\Fotos\20131010Duraton\" & x
'  MsgBox Nom

.Slides.Add(Index:=I, Layout:=ppLayoutBlank).Select

Set H = PresenPP.Slides(I)

'On Error Resume Next
ApliPP.ActiveWindow.Selection.SlideRange.Shapes.AddPicture(FileName:=Nom, LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, Left:=40, Top:=30, Width:=640, Height:=480).Select
On Error GoTo 0

I = I + 1
  x = Dir()
 Wend
End With
End Sub


Este otro código, un poco mas completo, recorre una hoja excel con una relación de fotos y las añade a una presentación PowerPoint, añadiendo, además, un cuadro de texto a cada foto.

Sub PPower()
Dim ApliPP As PowerPoint.Application
Dim PresenPP As PowerPoint.Presentation
Dim Diapo As PowerPoint.Slide
Dim Hoja
Dim Nom As String
Dim H
Dim DAnt, D, A As String
DAnt = ""
Set ApliPP = New PowerPoint.Application '

ApliPP.Visible = True
ApliPP.Activate
Set H = ActiveWorkbook.Sheets("Buscar")
Set PresenPP = ApliPP.Presentations.Add

With PresenPP
For Each Hoja In .Slides
Hoja.Delete
Next
End With

I = 1
j = 2
D = H.Range("d" & j).Value
DAnt = D
Nom = H.Range("d" & j) & H.Range("e" & j)
A = H.Range("h" & j).Value
  While Nom <> ""
 D = H.Range("d" & j).Value
 A = H.Range("h" & j).Value
If (D <> DAnt And Nom <> "") Or I > 100 Then
Set PresenPP = ApliPP.Presentations.Add
I = 1
DAnt = D
End If

PresenPP.Slides.Add(Index:=I, Layout:=ppLayoutBlank).Select


'On Error Resume Next
ApliPP.ActiveWindow.Selection.SlideRange.Shapes.AddPicture(Filename:=Nom, LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, Left:=40, Top:=30).Select ' Width:=640, Height:=480).Select
er = Error()
'ApliPP.ActiveWindow.Selection.SlideRange.Shapes.AddTextbox(msoTextOrientationHorizontal, 20, 400, 900, 30).Select
'ApliPP.ActiveWindow.Selection.TextRange.Text = Nom & " " & er
ApliPP.ActiveWindow.Selection.SlideRange.Shapes.AddTextbox(msoTextOrientationHorizontal, 20, 500, 900, 30).Select
ApliPP.ActiveWindow.Selection.TextRange.Text = A
On Error GoTo 0

I = I + 1
j = j + 1
Nom = H.Range("d" & j) & H.Range("e" & j)

DAnt = D

 Wend



'End With


End Sub


martes, 19 de diciembre de 2017

Gestor de archivos con excel. Buscar, encontrar, coincidir. Nuestro propio filtro avanzado en excel. Preliminar




Sigo sin ideas. El otro día hablando con un amigo me comentó que el utiliza un programa que le permite seleccionar fotos según unos atributos que el mismo les asigna. Además de arquitecto, diseña y construye muebles. A cada mueble construido le saca varias fotos para documentar el trabajo y, como es lógico, le interesa poder consultar en sus archivos por tipo de mueble, no solo por fecha o nombre. Asigna un tipo de mueble a cada foto, pueden ser varios atributos los asignados, tantos como se consideren necesarios para poder buscarlos por tipo de mueble.

Voy a hacer un gestor similar, solo con excel. Tengo, como muchísima gente, miles de fotos digitales en origen y unos cuantos cientos escaneadas. En las fotos digitales la fecha en la que se hicieron suele coincidir con la fecha que aparece en los listados. En las escaneadas no, la fecha de escaneo normalmente es muy posterior a la de realización de la foto. Podemos asignar un atributo "fecha de la foto" distinto al de fecha de los listados. Podemos asignar atributos tales como lugar, como familia, como amigos, etc...

Fase 1: Llevar a excel los nombres de las fotos:
  • Recupero el viejo D.O.S. Con el viejo comando dir obtengo un fichero con todos los "jpg" que tengo en mi directorio "Fotos", redireccionando la salida a un fichero de texto.
  • Creo un fichero ejecutable ".bat" (con notepad) con la siguiente instrucción: dir c:\DiscoWindowsXp\fotos\*.jpg /s /o /-C  > Imagenes.txt
  • Si quisiese añadir otro tipo de fichero añadiría una línea por tipo de fichero (dir c:\DiscoWindowsXp\fotos\*.gif /s /o /-C >> Imagenes.txt)
  • Esto nos da, me da en mi instalación, un fichero de texto con la siguiente estructura:



 Directorio de c:\DiscoWindowsXp\fotos\20121201 Confirmacion


01/12/2012  21:44           1407193 IMG_5543.JPG
01/12/2012  21:44           1467596 IMG_5544.JPG
              42 archivos 

En esta estructura  aparece una línea con el directorio y n líneas con el nombre, y otros atributos, de los ficheros. Debemos pasar de esta estructura a otra en la que en cada línea aparezca, además, el directorio, y que además elimine las líneas vacías.

  • Abro  excel. Desde excel abro el fichero de texto. En el momento de la apertura seleccionamos "Ancho fijo" y en origen del archivo "MS-DOS".
  • En la siguiente pantalla eliminamos todas las posibles divisiones. Vamos a importar los datos sin dividir.
  • En la tercera pantalla importamos los datos como "Texto". Finalizamos.
Adición del directorio al resto de las líneas:

  • La cosa consiste en identificar las líneas que empiezan por "Directorio ".
  • En el caso de que empiece por "Directorio" obtenemos el nombre del directorio y, si no, mantenemos el nombre obtenido anteriormente. 
  • Nos situamos en b2 y escribimos =SI(IZQUIERDA($A2;10)="Directorio";EXTRAE($A2;15;200);$B1)
  • Como quiero filtrar los directorios, en c2 ponemos y arrastramos la siguiente instrucción: =SI(IZQUIERDA($A2;10)="Directorio";$C1+1;$C1) Si los 10 caracteres de las izquierda son iguales a directorio, suma uno al valor anterior, si no mantén el valor anterior
  • Con esa instrucción pongo un número a cada directorio. 
  • Para numerar las fotos utilizamos la siguiente fórmula, en D2: =SI(MINUSC(DERECHA($A2;4))=".jpg";$D1+1;$D1)
  • Numeramos todas las líneas en E. Ponemos un 1 en E1, un dos en E2, seleccionamos ambas celdas y arrastramos.
Solo imágenes:
  • Insertamos una nueva hoja, "JPG" Copiamos la columna E en "JPG" A1, de momento no vamos a colocar cabeceras. 
  • Con el administrador de nombres creamos el rango con nombre "Datos". Con este nombre haremos referencia a al rango utilizado en la hoja "Imagenes", =Imagenes!$A:$E
  • Ya en JPG colocamos en b1 =COINCIDIR(JPG!$A1;Imagenes!D:D;0) Es decir buscamos el valor A1 en la columna D de Imagenes. Casi deberíamos incluir la gestión de errores pero de momento no es imprescindible. Arrastramos hasta el final.
  • En C1, en la columna C, situamos el directorio utilizando =SI.ERROR(INDICE(Datos;$B1;2);""). En este caso además controlamos el posible error con la función SI.ERROR() Si se produjera un error devuelve "". Arrastramos.
  • En D, utilizando =SI.ERROR(INDICE(Datos;$B1;1);"") traemos los nombres de los ficheros y su fecha y tamaño.
  • Esto es un paso intermedio, podemos separar fecha y nombre sin realizar este paso pero queda mas claro si se hace este paso intermedio. Evitemos, en lo posible, formulones.
  • En E1 situamos la fecha del fichero con =IZQUIERDA($D1;17). Arrastramos
  • Por último en F separamos el nombre y limpiamos de los espacios que preceden al nombre con =ESPACIOS(EXTRAE($D1;19;255)). Arrastramos
  • Podemos, si así lo consideramos, separar el año, el mes y el día de la fecha. Como, de momento la fecha está en modo texto, podemos convertirla a modo fecha. Basta sumarle 0 para convertirla. Gestionando el posible error, =SI.ERROR(E1+0;"")
  • Tanto si hemos pasada la fecha de texto a número como si no podemos utilizar las funciones DIA(E1), MES(E1), Año(G1), Hora(G1) y Minuto(G1). Gestionamos el posible error con SI.Error(). Arrastraríamos para completar la página.
Nombre de los directorios.
  • Insertamos una nueva hoja, la hoja "Dir".
  • Copiamos o llenamos la columna A con los 500 primeros números (+-)
  • Buscamos la primera ocurrencia del ordinal de la columna a en la columna C de "Imagenes" con =SI.ERROR(COINCIDIR(JPG!$A1;Imagenes!C:C;0);""). Esta vez si gestionamos el posible error. Arrastramos.
  • Obtenemos el nombre con =SI.ERROR(INDICE(Datos;$B1;2);"").
  • Vemos que como partimos de de un comando DOS tenemos problemas con la Ñ,ñ y con alguna vocal acentuada. 
  • Copiamos el carácter que sustituye a la Ñ (en "Imagenes" y procedemos a reemplazar en la hoja "Imagenes", columna A, ese carácter por "ñ".
  • Repetimos la operación para los otros posibles caracteres mal representados.
  • Ya tenemos separados, por columnas los atributos que nos interesan, pero, tenemos un libro excel cargadísimo de fórmulas que nos pueden causar problemas en un futuro.
Por tanto creo que debemos pasar los datos separados, copiando los valores solamente, a un nuevo libro
  • Creamos un nuevo libro.
  • Añadimos las hojas "JPG" y "Dir"
  • Vamos al libro procesado y copiamos los datos que nos interesen de los datos  obtenidos. En mi caso lo copio todo, ya eliminaré lo que tenga que eliminar. 
  • Copio JPG. Voy a la imagen, selecciono A1 y elijo "pegado especial". Seleccionamos "Valor".
  • Damos formato de fecha a la columna fecha
  • Lo mismo para Dir.
  • Insertamos una línea para incluir cabeceras. Eliminamos si fuese preciso alguna columna o alguna fila con errores.

¡Bien! ya tenemos importados a nuestra aplicación los datos que queremos gestionar. Ahora viene el pesadisimo  trabajo manual en el que tendríamos que poner, foto a foto, aquellos atributos que definen cada foto. Como tenemos agrupadas las fotos por directorio y es muy probable que todas las fotos de un mismo directorio tengan los mismos atributos, dividimos los atributos en "atributos del directorio" y "atributos de la foto". Los atributos del directorio los añadimos en la hoja de directorios y los otros en la hoja de JPG. Como hemos asignado unos atributos genéricos al directorio que afectan a todos los ficheros puede que resulte interesante definir un "no atributo" con el fin de excluir alguno de de los atributos de directorio de algún ficheros en concreto. 
A partir de aquí deberíamos de cambiar de plataforma, pasar los datos a una base de datos y trabajar con access en vez de excel, pero aun se pueden obtener resultados aceptables en excel.
  • Los atributos, en este caso, son texto separado por comas. Se puede hacer de otra manera, que cada cual se lo piense. 
  • Como estoy escribiendo un "preliminar" y veo que además el libro excel se está volviendo demasiado pesado, hay miles y miles de formulas,  no voy a desarrollar completamente la idea Me voy a limitar a encontrar un par de textos diferentes dentro del nombre del directorio y/o dentro de los atributos de directorio. De momento no voy a buscar ni por fechas ni por tamaños ni por atributos de fichero. Quizás lo desarrolle posteriormente
  • Asigno los atributos de algunos directorios en la página "Dir". Texto separado por comas. Estos atributos son texto del tipo "montaña", "vacaciones", "móvil", nombre de algún amigo, etc...
  • En la página "Buscar" dedicamos las celdas A2 y A3 para introducir los textos a buscar. En A5 indicamos si queremos que los textos buscados estén los dos en los atributos o con que este uno solo de ellos basta. Tiene dos valores válidos, "S" o "N", si o no.
  • Creamos un par de variables con nombre, Busca1 y Busca2, textos a buscar, referentes a Buscar!A2 y Buscar!A3.
  • Volvemos a la página "Dir". Como la segunda cadena de búsqueda es opcional, si no existiese la igualo a la primera., ver las celdas C1 y C2. Como puede hacerse directamente con variables con nombre creo la variable Busca3 y trabajo con ella =SI(Busca2<>"";MINUSC(Busca2);MINUSC(Busca1)).
  • Con este sencillo truco me evito varias columnas de fórmulas. Además trato las cadenas de texto en minúsculas, también facilita mucho la vida.
  • En las columnas C y D buscamos en la concatenación del nombre del directorio y de los atributos el primer y segundo texto a localizar con =SI.ERROR(ENCONTRAR( Busca1;MINUSC($A4 & "," & $B4 & ",");1);0).
  • En las columnas E y F utilizamos las funciones Y() y O() para conocer si al menos uno de los textos buscados esta presente o si ambos lo están.
  • Como ya he comentado, una vez que tenemos importados y procesados los datos a la hoja excel deberíamos continuar pasando los datos a una base de datos, tipo access,  y continuar el trajo con la B.D. En este punto debemos hacer un "JOIN" con los directorios y los ficheros JPG. Entre la hoja Dir y la hoja JPG.
  • Primero buscamos, y encontramos, el directorio de JPG en la relación de directorios de Dir con =COINCIDIR(JPG!B2;Dir!A:A;0) en la columna K. 
  • El valor encontrado nos permite pasar de Dir a JPG los distintos campos del JOIN con =INDICE(Dir!B:B;$K2)
  • En la columna P numeramos los registros que cumplen la/las condiciones pedidas con =SI(SI(AmbosN="S";$O2;$N2);P1+1;P1).
  • Volvemos a la hoja "Buscar". En la columna B hemos copiado la numeración de uno a n, donde n es el número máximo de registros esperados. Si nos hubiésemos quedado cortos ampliamos numeración y arrastramos las formulas
  • Buscamos el ordinal (1,2,3,4...) en la columna P de JPG. Con este número obtenemos los distintos campos a presentar con =SI.ERROR(INDICE(JPG!B:B;Buscar!$C2) & "\";"")
  • Tanto la columna P de JPG, como el área de datos de JPG deberíamos referenciarlas con una variable con nombre. 
  • Para terminar escribimos un código html que lo podemos pasar a una página htm.
  • =SI(E2<>"";"<br><a href=" &CARACTER(34) & D2& E2 &CARACTER(34)& " target=foto>"  & D2& E2 & "</a>";"")
  • Pasamos este código, es un copia-pega manual, abrimos la página y ya tenemos un enlace a todas las fotos que cumplen las condiciones pedidas. 
  • Si queremos completar, dar un acabado perfecto, ya tendríamos que pasar a programación.






jueves, 7 de diciembre de 2017

Automatizar respuestas a un formulario de Google con Excel. Preliminar.

En un principio la idea de automatizar respuestas a un formulario de google me surgió en uno de mis trabajos con Arduino Yun. Parto del supuesto de que necesito medir remotamente unos determinados parámetros. Leo, envío a la nube los valores medidos y puedo consultarlos desde cualquier sitio (incluido mi móvil).
Me quedé sin ideas y dejé de hacer cosas con arduino. El otro día en una sobremesa estuvimos hablando de IPs estaticas e IPsdinámicas, si se podía hacer esto o no hacerlo, que si te cambia la IP no puedes pensar en establecer tu propia red, etc...

Me surgió la pregunta ¿puedo conocer remotamente la IP dinámica de mi instalación desde cualquier sitio? Después de pensarlo, después de hacer unas cuantas  pruebas recuperé la vieja idea de automatizar respuestas a un formulario.
  • Obtengo la IP. Es fácil. De momento, estoy en los preliminares, la leo de una de las páginas web que me dan ese servicio (www.cualesmiip.com). 
  • Esta lectura la puedo hacer automaticamente abriendo www.cualesmiip.com desde vbasic como si fuera un libro excel mas.
  • Workbooks.Open Filename:="http://www.cualesmiip.com/"
  • Hecho esto, en principio, la dirección IP aparece en la celda A31.
  • Esto no quiere decir que siempre vaya a ser así, la página web puede ser modificada en cualquier momento.
Creo un formulario google, con salida a una hoja de cálculo:


Si quiero automatizar el envío de un formulario necesito conocer tanto la acción que se ejecuta al pulsar "Envío" como el nombre de los distintos campos de pregunta. Son nombres internos que hay que buscar en el código fuente del formulario:
  • El la inmensa sopa de letras que supone el código fuente de un formulario encontrar la acción y los nombres de las preguntas parece imposible pero es relativamente sencillo. 




Una vez encontrados acción y preguntas lo llevamos un código vbasic, como el siguiente:



Sub DireccionIP()

Dim IP, NL, Accion, Prg1, Prg2, Lin

'
' Abrimos y obtenemos IP de www.cualesmiip
'
    Workbooks.Open Filename:="http://www.cualesmiip.com/"
  IP = ActiveSheet.Range("a31").Value
    ActiveWindow.Close
'Preparamos respuesta al formulario
Accion = "https://docs.google.com/forms/d/e/1FAIpQLScChBMMMdog1LT4leKk2WF0DDd32-aeWLll57YjVVjvBvJGhw/formResponse?"
Prg1 = "entry.1464650708=" & IP
Prg2 = "entry.1464650708=" & Now()


Lin = Accion & Prg1 & "&" & Prg2

'enviamos la acción

    Workbooks.Open Filename:=Lin
  ActiveWindow.Close
    
End Sub


  • Ya solo queda comprobar que el envío se ha realizado. Voy a mi google drive, abro la hoja de cálculo que he creado para contener las repuestas y veo que si se ha producido el envío. 
  • Por triplicado, de momento no se por que, pero ahí está la dirección IP pedida.
  • Como estoy en los preliminares, me doy casi por satisfecho, aunque el resultado presente varios defectos y falte casi totalmente el desarrollo de la idea, he conseguido enviar vía excel la dirección IP obtenida en www.cualesmiip.com a mi google drive. Ya la tengo en red, ya puedo consultarla desde cualquier sitio. De momento se que se puede hacer de un modo relativamente sencillo.