Metadata-Version: 2.4
Name: sarapy
Version: 6.1.0
Summary: Library for Sarapico Metadata processing
Author-email: Lucas Baldezzari <lmbaldezzari@gmail.com>
License: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
Classifier: Operating System :: Unix
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENCE
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5
Requires-Dist: scipy>=1.9
Requires-Dist: scikit-learn>=1.2
Requires-Dist: matplotlib>=3.6
Requires-Dist: seaborn>=0.12
Requires-Dist: requests>=2.28
Requires-Dist: python-dotenv>=1.0
Requires-Dist: geopy>=2.3
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Dynamic: license-file

# SARAPY

Library for processing SARAPICO project metadata of _AMG SA_.

#### Versión 6.1.0

**Se corrigen tres crashes en el procesamiento de operaciones.** El más grave rompía el
pipeline completo a partir de la **segunda** llamada a `processOperations()` sobre una misma
instancia de `OpsProcessor` — es decir, el modo de uso en streaming/producción. No se había
detectado porque los scripts de análisis (`test/mergingdata.py`) crean un `OpsProcessor` nuevo
en cada iteración.

- `OpsProcessor.updateOperationsDict()` ya **no muta** `newSample`. Antes hacía
  `sample_ops = newSample` (misma referencia) y luego `sample_ops += last_op`, donde `last_op`
  es un **dict**: en Python `lista += dict` appendea las **claves** como strings, corrompiendo
  la muestra. A partir de la 2da llamada el pipeline fallaba con
  `AttributeError: 'str' object has no attribute 'keys'` al construir el DataFrame.
- La última operación de la muestra anterior ahora se **antepone** (no se appendea), que es lo
  que el recorte `classified_ops[1:]` de `classifyForPlantin()` siempre asumió.
- `updateAfterAwake()` pasa a ejecutarse **antes** de ese recorte: su máscara de `N_MODE` se
  arma sobre `sample_ops` completo, y aplicarla después producía
  `IndexError: boolean index did not match indexed array`.
- `FertilizerTransformer.transform()` ya no rompe con `SC_FT` nulo. `TransformInputData` deja
  `None` cuando el `csv_datum` viene corto, y ese valor llegaba como `NaN` a
  `PolynomialFeatures` (`ValueError: Input X contains NaN`). Ahora esas operaciones se
  devuelven como `NaN` — manteniendo el shape `(n,)` alineado con la entrada — y se loguea un
  warning con la cantidad de ops afectadas.
- `FertilizerTransformer.__init__()` **re-lanza** si no puede cargar los `.pkl`. Antes capturaba
  `FileNotFoundError`, logueaba y seguía, dejando `_regresor` / `_poly_features` sin asignar; el
  error aparecía mucho después como `AttributeError` lejos de la causa. Además ahora se capturan
  todos los errores de carga (pickle corrupto, mismatch de versión de sklearn), no sólo el archivo faltante.
- `FertilizerTransformer.transform()` usa `.transform()` en lugar de `.fit_transform()` sobre el
  `PolynomialFeatures` cargado. Re-fitear el artefacto en cada llamada lo mutaba y anulaba el
  sentido de picklearlo. **Los gramos estimados no cambian.**
- Nuevo guard en `processOperations()`: verifica que `timestamps`, `pl_clas` y `ft_grams` tengan
  el mismo largo antes del `np.column_stack`, con un mensaje explícito en vez de un error opaco de numpy.

Los resultados **no cambian** para el camino de una sola llamada a `processOperations()` (que es
el que venía funcionando): con `last_oprc=None` no hay fila antepuesta ni recorte.

Además:

- El bloque `if __name__ == "__main__"` de `OpsProcessor.py` ahora reporta, por nodo, el uso de
  fertilizante en gramos: **total** (contando ops 0 y 1), **promedio por operación válida**
  (sólo ops etiquetadas como 1) y **fertilizante perdido** (suma sobre ops etiquetadas como 0,
  con su porcentaje). El total es igual en los tres modos de clasificación — los gramos salen
  de `SC_FT` y no dependen de la etiqueta de plantín —; lo que cambia es cómo se reparte entre
  válido y perdido, así que la métrica debe leerse siempre junto al modo.
- El mismo bloque imprime los valores crudos del sensor de fertilizante (`SC_FT`): mínimo,
  máximo y promedio por nodo.
- Se agregan `CLAUDE.md` y `AGENTS.md` (en inglés) con la arquitectura de la librería, las
  trampas conocidas y la política de versionado.

#### Versión 6.0.0

**El RFID no leído (`4294967295`) pasa a ser una operación normal.** La electrónica emite el
sentinel `0xFFFFFFFF` en `ID_OPRR` / `ID_CDLL` cuando no logra leer el RFID. Hasta la 5.1.0 la
librería interpretaba eso como *operación inválida*; ahora se interpreta como lo que es: la
operación es real y se clasifica igual que cualquier otra, y lo único que se desconoce es la
**identidad** del operario.

Esto **cambia los resultados**. En `examples/` el sentinel aparece en el 4,54% de las ops
(11.644 / 256.384, siempre en `ID_OPRR`, nunca en `ID_CDLL`) y hay 61 de 149 nodo/día donde
está en el 100% de las operaciones. Antes, en esos nodo/día no se detectaba ni un lagarto y
las distancias salían enteramente `NaN`.

Cambios de API (breaking):

- `LagartoDetector.detect_lagartos`, `HardClassifier.label_ops_by_distance`,
  `DistanceMetrics.compute_distances_by_tag` y sus wrappers `*_from_rows` **ya no aceptan**
  `worker_codes` / `work_crew_codes`. La clasificación es puramente geométrica.
- `PlantinClassifier.classify` ya no acepta `worker_codes` / `work_crew_codes`.
- Se elimina el flag `hard_use_rfid` de `OpsProcessor`. Su único efecto era forzar
  `tag_seedling = 1` en las lecturas fallidas, que es lo contrario de la política nueva.
- `HardClassifier.classify_from_rows` ya no acepta `use_rfid`.
- `valid_mask` ahora es `False` **sólo** por ausencia de coordenadas (antes también por RFID).
- Nuevo helper `sarapy.dataProcessing.is_rfid_unread(code)`: predicado de **reporte** para
  contar lecturas fallidas. No interviene en ninguna decisión de clasificación.

#### Versión 5.1.0

- Se ajustan los umbrales por defecto de detección de lagartos a los valores que mejores
  resultados dieron en el barrido de `test/comparacion_medias_1s.py` (preset "Intermedio"):
  `lagarto_min_dist_m` pasa de `0.8`/`1.0` a **`1.5`** y `lagarto_min_seq_len` de `3` a **`2`**
  (`lagarto_same_place_m=0.8` y `lagarto_max_dist_m=None` se mantienen). El cambio se aplica a
  los defaults de `LagartoDetector.detect_lagartos`, `PlantinClassifier.classify` y
  `OpsProcessor._classifyHard`, y a los ejemplos de `test/checking_lagartos.py`.
- Empíricamente, en estos datasets la palanca dominante es `lagarto_min_dist_m`; `lagarto_min_seq_len`
  casi no mueve el resultado. NO bajar `lagarto_min_seq_len` a `1` (re-etiquetaría todo cero aislado).

```python
##argumentos del método PlantinClassifier.classify() — umbrales de lagarto recomendados
kwargs_classifier = {"proba_threshold":0.45,
                        "use_proba_ma":False,
                        "proba_ma_window":10,
                        "update_samePlace":True,
                        "update_dstpt":True,
                        "umbral_proba_dstpt":0.5,
                        "umbral_bajo_dstpt":1.5,
                        "use_ma":True,
                        "dstpt_ma_window":62,
                        "use_min_dstpt":False,
                        "factor":0.1,
                        "detect_lagartos": True,
                        "label_lagartos_as_1": False,
                        "lagarto_min_dist_m": 1.5,
                        "lagarto_same_place_m": 0.8,
                        "lagarto_min_seq_len": 2,
                        "lagarto_max_dist_m": None,  # None = sin tope; p.ej. 15.0 descarta saltos de GPS
                        "useRatioStats":False,
                        "std_weight":1.,
                        "useDistancesStats":False,
                        "ratio_dcdp_umbral":0.1,
                        "dist_umbral":1.,
                        }
```

##### Cómo clasificar: ML, ML + re-etiquetado de lagartos, y Hard

`OpsProcessor` expone tres modos de clasificación de plantín. El modo se elige con tres
flags que se pasan a `processOperations(...)` (o dentro de `kwargs_classifier`):

| Modo | `use_hard_classifier` | `detect_lagartos` | `label_lagartos_as_1` |
|------|:---:|:---:|:---:|
| **ML** (solo el clasificador entrenado) | `False` | `False` | `False` |
| **ML + re-etiquetado de lagartos** | `False` | `True` | `True` |
| **Hard + re-etiquetado de lagartos** | `True` | `True` | `True` |

> **Nota:** con `use_hard_classifier=True` las etiquetas salen del `HardClassifier`
> (reglas, sólo distancia) y **el ML NO se ejecuta** — el Hard reemplaza al ML, no se
> combinan. El agrupamiento "mismo lugar" es intrínseco al Hard (el flag `update_samePlace`
> sólo afecta al camino ML). El re-etiquetado de lagartos se aplica en cualquiera de los dos
> caminos cuando `detect_lagartos` y `label_lagartos_as_1` están en `True`.

Usando los `kwargs_fmcreator` / `kwargs_hard` / `kwargs_classifier` de los bloques de arriba:

```python
import json
from sarapy.dataProcessing.OpsProcessor import OpsProcessor

op = OpsProcessor(
    classifier_file="modelos/pipeline_rf.pkl",
    regresor_file="modelos/regresor_v2.pkl",
    poly_features_file="modelos/poly_features_v2.pkl",
    **kwargs_hard, **kwargs_fmcreator,
)

with open("examples/2026-02-25/UPM047N/historical-data.json") as f:
    samples = json.load(f)

# Los tres modos se arman sobreescribiendo los flags sobre kwargs_classifier.
# (Se mergea en un solo dict para no pasar el mismo argumento dos veces.)

# 1) Sólo ML
out_ml = op.processOperations(
    samples,
    **{**kwargs_classifier, "use_hard_classifier": False,
       "detect_lagartos": False, "label_lagartos_as_1": False},
)

# 2) ML + re-etiquetado de lagartos
out_ml_lag = op.processOperations(
    samples,
    **{**kwargs_classifier, "use_hard_classifier": False,
       "detect_lagartos": True, "label_lagartos_as_1": True},
)

# 3) Hard + re-etiquetado de lagartos (el Hard reemplaza al ML)
out_hard = op.processOperations(
    samples,
    **{**kwargs_classifier, "use_hard_classifier": True,
       "detect_lagartos": True, "label_lagartos_as_1": True},
)

# processOperations devuelve una lista de dicts (una por operación):
#   [{"timestamp": ..., "tag_seedling": 0/1, "tag_fertilizer": gramos (float)}, ...]
```

> Si no se pasa ningún flag, los valores por defecto de `OpsProcessor` son
> `use_hard_classifier=True`, `detect_lagartos=True` y `label_lagartos_as_1=True`
> (modo **Hard + re-etiquetado de lagartos**). **Ojo:** el bloque `kwargs_classifier`
> de arriba trae `label_lagartos_as_1=False`, así que si lo pasás tal cual el
> re-etiquetado de lagartos queda apagado salvo que lo sobreescribas (como en los ejemplos).

#### Versión 5.0.0

- Se implementa HardClassifier.

```python
## argumentos de PlantinFMCreator

kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3,
                    "dist_mismo_lugar":0.8, "max_dist":100,
                    "umbral_ratio_dCdP":2, "deltaO_medio":4,
                    "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5,
                    "deltaO_ma": True, "deltaO_ma_window": 26}

##argumentos del método PlantinClassifier.classify() (clasificador VIEJO / ML)
label_lagartos_as_1 = True
kwargs_classifier = {"proba_threshold":0.45,
                        "use_proba_ma":False,
                        "proba_ma_window":10,
                        "update_samePlace":True,
                        "update_dstpt":True,
                        "umbral_proba_dstpt":0.5,
                        "umbral_bajo_dstpt":1.5,
                        "use_ma":True,
                        "dstpt_ma_window":62,
                        "use_min_dstpt":False,
                        "factor":0.1,
                        "detect_lagartos": True,
                        "label_lagartos_as_1": label_lagartos_as_1,
                        "lagarto_min_dist_m": 0.8,
                        "lagarto_same_place_m": 0.8,
                        "lagarto_min_seq_len": 3,
                        "lagarto_max_dist_m": None,  # None = sin tope; p.ej. 15.0 descarta saltos de GPS
                        "useRatioStats":False,
                        "std_weight":1.,
                        "useDistancesStats":False,
                        "ratio_dcdp_umbral":0.1,
                        "dist_umbral":1.,
                        }

##argumentos del HardClassifier (clasificador NUEVO / sólo distancia)
kwargs_hard = {"umbral_mismo_lugar": 0.8, "dist_max": 5.0}
```

#### Version 4.0.0

- Se implementa mejora en la detección de lagartos.

- Las keys nuevas que se recomienda usar en `kwargs_classifier` son:

    ```python
    kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3,
                        "dist_mismo_lugar":0.8, "max_dist":100,
                        "umbral_ratio_dCdP":2, "deltaO_medio":4,
                        "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5,
                        "deltaO_ma": True, "deltaO_ma_window": 26}
    ```

    ```python
    ##argumentos del método PlantinClassifier.classify()
    label_lagartos_as_1 = False
    kwargs_classifier = {"proba_threshold":0.45,
                            "use_proba_ma":False,
                            "proba_ma_window":10,
                            "update_samePlace":True,
                            "update_dstpt":True,
                            "umbral_proba_dstpt":0.5,
                            "umbral_bajo_dstpt":1.5,
                            "use_ma":True,
                            "dstpt_ma_window":62,
                            "use_min_dstpt":False,
                            "factor":0.1,
                            "detect_lagartos": True,
                            "label_lagartos_as_1": label_lagartos_as_1,
                            "lagarto_min_dist_m": 0.8,
                            "lagarto_same_place_m": 0.8,
                            "lagarto_min_seq_len": 3,
                            "lagarto_max_dist_m": None,  # None = sin tope; p.ej. 15.0 descarta saltos de GPS
                            "useRatioStats":False,
                            "std_weight":1.,
                            "useDistancesStats":False,
                            "ratio_dcdp_umbral":0.1,
                            "dist_umbral":1.,
                            }
    ```

#### Version 3.4.0

- Se reescribe la detección de lagartos en `PlantinClassifier` usando el algoritmo basado en
  **distancias** definido en [docs/lagartos_plan.md](docs/lagartos_plan.md) (antes sólo se miraban
  corridas de ceros en las etiquetas). Ahora un lagarto es una secuencia de `>= lagarto_min_seq_len`
  operaciones consecutivas no plantadas (`0`) separadas por `> lagarto_min_dist_m`, tratando las
  operaciones de "mismo lugar" (`< lagarto_same_place_m`) como transparentes.
- La detección corre **siempre** (`detect_lagartos=True`) y almacena los lagartos detectados en el
  atributo `PlantinClassifier.lagartos` (lista de dicts: `start`, `end`, `indices`, `length`,
  `mean_dist`). El flag `label_lagartos_as_1` decide si las operaciones del lagarto se re-etiquetan a `1`.
- Se eliminan los métodos viejos (`_find_lagartos`, `_split_run`, `detect_and_fix_lagartos`,
  `_fix_short_lagartos`, `_chek_low_dstpt`) y las keys `fix_lagartos` / `umbrales_lagartos`.

#### Version 3.3.0

- Se agrega feature para la detección y arreglo de operaciones dentro de lagartos.
- Los keys para FMCreator y Classifier quedan así:

    ```python

    ## argumentos de PlantinFMCreator
    kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3,
                        "dist_mismo_lugar":0.2, "max_dist":100,
                        "umbral_ratio_dCdP":2, "deltaO_medio":4,
                        "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5,
                        "deltaO_ma": True, "deltaO_ma_window": 26}
            
    ##argumentos del método PlantinClassifier.classify()
    kwargs_classifier = {"proba_threshold":0.45,
                            "use_proba_ma":False,
                            "proba_ma_window":10,
                            "update_samePlace":True,
                            "update_dstpt":True,
                            "umbral_proba_dstpt":0.5,
                            "umbral_bajo_dstpt":1.5,
                            "use_ma":True,
                            "dstpt_ma_window":62,
                            "use_min_dstpt":False,
                            "factor":0.1,
                            "fix_lagartos": False,
                            "umbrales_lagartos": (1,5),
                            "useRatioStats":False,
                            "std_weight":1.,
                            "useDistancesStats":False,
                            "ratio_dcdp_umbral":0.1,
                            "dist_umbral":1.,
                            }
    ```

#### Version 3.2.0

- Se modifica función para detectar operaciones en el mismo lugar de tal forma de no considerar efectos temporales.

#### Version 3.1.1

- Se vuelve a generar archivos de regresor_v2 y poly_features_v2 porque quedó mal cargado.

#### Version 3.1.0

- Se actualiza regresor para estimar fertilizante.
- Actualización de archivos para instalar la libería.


#### Version 3.0.0
- Se mejora la forma de obtener valores de media movil para todas las variables en las que se usa.
- Se corrigen bugs debido a nodos con pocas operaciones.
- Se corrigen errores a la hora de pasar parámetros a los métodos de algunas clases.
- Se configuran parámetros de fmcreator y plantin_classifier para el reetiquetado, los mismos son:

    ```python
    kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3,
                            "dist_mismo_lugar":0.2, "max_dist":100,
                            "umbral_ratio_dCdP":2, "deltaO_medio":4,
                            "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5,
                            "deltaO_ma": True, "deltaO_ma_window": 26}
            
            
    ##argumentos del método PlantinClassifier.clasiffy()
    kwargs_classifier = {"proba_threshold":0.4,
                         "use_proba_ma":False,
                         "proba_ma_window":10,
                         "update_samePlace":True,
                         "update_dstpt":True,
                         "umbral_proba_dstpt":0.5,
                         "umbral_bajo_dstpt":1.5,
                         "use_ma":True,
                         "dstpt_ma_window":62,
                         "use_min_dstpt":False,
                         "factor":0.1,
                         
                         "useRatioStats":False,
                         "std_weight":1.,
                         "useDistancesStats":False,
                         "ratio_dcdp_umbral":0.1,
                         "dist_umbral":0.5,
                         }

    ```

#### Version 2.3.0

- Se agregan funcionalidades.
- Se corrigen errores menores.

#### Version 2.2.0

- Se agrega baseDeltaP en PlantinFMCreator para poder dividir el timestamp de la electrónica por 10, ya que se envía en décimas de segundo.
   
#### Version 2.1.1

- Se corrige error de tiepo en TransformToOutputData.

#### Version 2.1.0

- Se modifica TransformInputdata para poder obtener el timestamp en newSample de OpsProcessor. Se modifica transformOutputData para entregar los datos en base a la solicitud de #43. Se modifica OpsProcessor para poder obtener los datos de salida según solicitud en #43. Close #43.

#### Version 2.0.0

- Se realizan cambios en TransformInputData para que convierta los datos de telemetría a la forma de lista de diccionarios, como un JSON, para que sea más fácil de usar y entender. Además, a futuro, se espera que los datos de la electrónica se puedan enviar en este formato.
- Se realizan cambios en TLMSensorDataProcessor para que pueda recibir los datos de telemetría como una lista de diccionarios. La clase permite obtener los datos como un numpy array, o indexar por filas y columnas de forma similar a un DataFrame de pandas (de hecho se usa pandas para esto).
- Se generan cambios en PlantinFMCreator para que pueda recibir los datos de telemetría como una lista de diccionarios, y se usa TLMSensorDataProcessor para procesar los datos y obtener la matriz de características, la cual es la misma que antes.
- Se generan cambios en FertilizerTransformer para que pueda recibir los datos de telemetría como una lista de diccionarios, y se usa TLMSensorDataProcessor para procesar los datos y obtener la matriz de características, la cual es la misma que antes.
- Se generan cambios en OpsProcessor para poder trabajar con el formato nuevo de datos.

Los detalles de los cambios son comentados en el issue #37.

#### Version 1.4.0b1

- Se empieza a trabajar sobre librería estadística para poder detectar sensores saturados.
- Se empieza a trabajar sobre actualización para trabajar con los datos en la nueva modalidad luego de la migración.

#### Version 1.3.1

- Se modifica PlantinClassifier para tomar el umbral máximo de dst_pt en 4 y no en 7.

#### Version 1.3.0

- Se agrega funcionalidad para estimar la cantidad de gramos de fertilizante en base al nivel de distorsión de fertilizante arrojado por la electrónica. Se implementa mlProcessor.FertlizerFMCreator y mlProcessor.FertilizerTransformer. Además se modifican las clases OpsProcessor y TransformToOutputData para poder usar estas nuevas clases.

#### Version 1.2.6

- Se agrega línea dentro de clase OpsProcessor.

#### Version 1.1.6

- Se modifica PlantinClassifier para mejorar el NO conteo de plantines en OSP.

#### Version 1.1.5

- Se quita print de función update.

#### Version 1.1.4

- Se implementa actualización de operaciones con bandera MODE en 1. Se hacen operaciones de plantin iguales a 0 para todas las operaciones con MODE = 1.

#### Version 1.1.3

- Se modifica GeoProcessor para no tener problemas con valores de latitud y longitud fuera de rangos.

#### Version 1.1.2

- Se modifica TimeSeriesProcessor.transform() para poder usar la modificación realizada en 1.1.1.

#### Version 1.1.1

- Se modifica TimeSeriesProcessor.compute_ratio_dCdP() dado que la versión de vectorize al parecer no funcionaba correctamente en ciertos casos.

#### Version 1.1.0

Versión 1.1 estable para trabajarse en servidor.

- Se implementa nueva estrategia para la clasificación de plantines.


#### Version 1.0.1

- Se agrega *__init.py__* dentro del mpdulo _utils_.

#### Version 1.0.0

- Se crean clases TransformInputData y TransformToOuputData dentro del módulo proprocessing. Se crean utils.

#### Version 0.4.9

- Se cierra la versión 0.4.8 y se crea la versión 0.4.9 para actualizar repositorio, diagrama de clases a esta versión y la Licencia de uso.

#### Version 0.4.8

- Se importa pandas en OpsProcessor.py ya que no estaba.

#### Version 0.4.7

- Se agregan modificaciòn en método OpsProcessor.transformInputData() y se agrega OpsProcessor.transformToOutputData().

#### Version 0.4.6

- Se agrega función OpsProcessor.transformInputData() para convertir la lista de diccionarios entregadas por el decoder a un array de strings necesarios para procesar y clasificar los datos.

#### Version 0.4.5

- Se modifica clase PlantinClassifier para que ahora tome un clasificador y lo use para clasificar operaciones.
- Se modifica OpsProcessor para poder obtener clasificaciones (y no matrices de características de plantin como se venía probando).

#### Version 0.4.4

- Se modifica fit() de PlantinFMCreator.

#### Version 0.4.3

- Se agrega fit() dentro de transform() de PlantinFMCreator.

#### Version 0.4.2

- Se agrega \*\*kwargs en OpsProcessor, PlantinClassifier y PlantinFMCreator para poder setear los atributos de PlantinFMCreator desde las clases que lo usen.

#### Version 0.4.1

- Se corrigen problemas de importaciones circulares.

#### Version 0.4.0

- Se implementa _OpsProcessor_.
- Se implementa _PlanntinClassifier_.
- Se corrige salida de _transform()_ y _fit_transform()_ de GeoProcessor.
- Se mueve PlantinFMCreator a mlProcessors
- Se cambia nombre de TLMSensorDataCreator a TLMSensorDataProcessor
