Restaurar vista previa en carpetas de red tras actualizaciones de Windows

De pronto en el trabajo tras una actualización de seguridad de W10 en el trabajo algunos usuarios que usaban de forma intensiva la vista previa en el explorador dejaron de tener acceso a la vista previa , mucha gente no la usa , pero para el que esta acostumbrado suele ayudar bastante al no ir a ciegas antes de abrir cualquier archivo

La causa principal del problema no es un error, sino un cambio de seguridad intencional. Microsoft bloqueó la vista previa de archivos en ubicaciones de red clasificadas como “zona Internet” a partir de las actualizaciones de octubre 2025 (KB5066791 para Windows 10) para prevenir una vulnerabilidad que permitía fugas de hashes NTLM. La solución más efectiva para carpetas NAS es agregar las rutas de red a la zona de Intranet Local o Sitios de Confianza en Windows.

¿ Por qué las actualizaciones rompen esta funcionalidad ?

El cambio afecta específicamente cómo Windows maneja los archivos con “Mark of the Web” (MotW) y los ubicados en zonas de seguridad consideradas riesgosas. Cuando se previsualiza un archivo, los preview handlers pueden cargar recursos externos referenciados, y si estos apuntan a rutas UNC o URLs file:, Windows puede enviar credenciales NTLM hasheadas a servidores externos.

KB específicos que causan el problema: KB5066791 (Windows 10, octubre 2025) y KB5066835 (Windows 11). Estas actualizaciones modifican el valor URLACTION_SHELL_PREVIEW (0x180F) en la Zona Internet de “Enable” a “Disable”. Desinstalar estos parches no es solución permanente ya que el comportamiento se reimplementa en todas las actualizaciones de seguridad posteriores.

Soluciones al problema :

Opción 1

Crear un archivo de texto con el Bloc de notas y guárdalo como agregar_nas.reg:

Con el contenido

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1]
":Range"="10.57.45.XX"
"*"=dword:00000001

Lo importamos y reiniciamos explorer.exe

Ya tenemos nuestra vista previa funcionando

Si entrásemos en el editor del registro veríamos los valores importados

Opción 2

Abrir PowerShell como Administrador 

New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" -Force
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" -Name ":Range" -Value "10.57.45.XX" -PropertyType String -Force
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" -Name "*" -Value 1 -PropertyType DWord -Force

Poe supuesto como mas rapida y directa la opción 1

Y con esto y un bizcocho …..

Sensor arcón congelador ZT08 e integración en Home Assistant

Hace unas semanas vi un termómetro zigbee con una sonda externa que me podia ir bien para el arcón congelador que tengo , el enlace de Aliexpres es este

Lo elegí porque el que tenia antes a partir de -20ºC tenia problemas y no daba lectura , el mínimo teórico de este dispositivo son -40ºC

Se puede colocar de diferentes maneras , desde magnética , adhesiva y con ventosa , al final me decante por la adhesiva en la tapa de las baterías.

Va alimentado por tres pilas AAA

Al alimentarlo ya nos muestra la temperatura local , la de las sonda , la hora y el nivel de bateria , pero las temperaturas en grados Fahrenheit

El siguiente paso es integrarlo en zigbee2mqtt , la información de este dispositivo será la siguiente.

Nada mas emparejarlo nos dice que no esta soportado , y nos devuelve este identificador “_TZE284_hodyryli

Para disponer de el tendremos que usar un converter , aquí encontre uno que funcionaba , el código seria el siguiente :

const tuya = require('zigbee-herdsman-converters/lib/tuya');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const e = exposes.presets;
const ea = exposes.access;

const fzLocal = {
    tuya_weather_station: {
        cluster: 'manuSpecificTuya',
        type: ['commandDataReport', 'commandActiveStatusReport', 'commandMcuSyncTime'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            
            // Time synchro
            if (msg.type === 'commandMcuSyncTime') {
                (async () => {
                    try {
                        const endpoint = msg.endpoint;
                        const now = new Date();
                        
                        const utcTime = Math.round(now.getTime() / 1000);
                        const localTime = utcTime - (now.getTimezoneOffset() * 60);
                        
                        const utcArray = [
                            (utcTime >> 24) & 0xFF,
                            (utcTime >> 16) & 0xFF,
                            (utcTime >> 8) & 0xFF,
                            utcTime & 0xFF,
                        ];
                        
                        const localArray = [
                            (localTime >> 24) & 0xFF,
                            (localTime >> 16) & 0xFF,
                            (localTime >> 8) & 0xFF,
                            localTime & 0xFF,
                        ];
                        
                        const payload = {
                            payloadSize: 8,
                            payload: [...utcArray, ...localArray],
                        };
                        
                        await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {disableDefaultResponse: true});
                        
                        // set 24h time format
                        await new Promise(resolve => setTimeout(resolve, 500));
                        try {
                            await tuya.sendDataPointBool(endpoint, 17, false);
                        } catch (e) {
                            // Ignore if DP 17 don't exist
                        }
                        
                    } catch (error) {
                        // Ignore time synchro errors
                    }
                })();
                
                return {};
            }
            
            if (!msg.data || !msg.data.dpValues) return {};
            
            for (const dpValue of msg.data.dpValues) {
                const dp = dpValue.dp;
                const data = dpValue.data;
                
                let value;
                // temperature
                if (dpValue.datatype === 2) {
                    // Reads the data as an unsigned big-endian 32-bit integer (Negative numbers will be wrong, eg. 429496724.6)
                    // value = data.readUInt32BE(0);
                    // Reads the data as a signed big-endian 32-bit integer (Negative numbers will be correct)
                    value = data.readInt32BE(0);
                } else if (dpValue.datatype === 4) {
                    value = data[0];
                } else {
                    value = data[0];
                }
                
                switch (dp) {
                    // temperature
                    case 1:
                        result.temperature = value / 10;
                        break;
                    // humidity
                    case 2:
                        result.humidity = value;
                        break;
                    // battery_state
                    case 3:
                        result.battery_state = value;
                        result.battery = value === 0 ? 10 : (value === 1 ? 50 : 100);
                        result.battery_low = value === 0;
                        break;
                    // time_format
                    case 17:
                        result.time_format = value ? '12h' : '24h';
                        break;
                    // temperature_external
                    case 38:
                        result.temperature_external = value / 10;
                        break;
                }
            }
            
            return result;
        },
    },
};

const definition = {
    fingerprint: tuya.fingerprint('TS0601', ['_TZE284_hodyryli']),
    model: 'TS0601_weather_station',
    vendor: 'TuYa',
    description: 'Weather station with clock, internal/external temperature and humidity',
    fromZigbee: [fzLocal.tuya_weather_station],
    toZigbee: [tuya.tz.datapoints],
    configure: tuya.configureMagicPacket,
    exposes: [
        e.temperature().withDescription('Internal temperature'),
        e.humidity().withDescription('Internal humidity'),
        e.numeric('temperature_external', ea.STATE)
            .withUnit('°C')
            .withDescription('External temperature sensor'),
        e.battery()
            .withDescription('Battery level (10%=low, 50%=medium, 100%=full)'),
        e.battery_low()
            .withDescription('Battery low warning'),
        e.enum('battery_state', ea.STATE, [0, 1, 2])
            .withDescription('Raw battery state (0=low, 1=medium, 2=full)'),
        e.enum('time_format', ea.STATE, ['12h', '24h'])
            .withDescription('Clock time format'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'temperature', tuya.valueConverter.divideBy10],
            [2, 'humidity', tuya.valueConverter.raw],
            [3, 'battery_state', tuya.valueConverter.raw],
            [17, 'time_format', tuya.valueConverter.onOff],
            [38, 'temperature_external', tuya.valueConverter.divideBy10],
        ],
    },
};

module.exports = definition;

Crearemos el fichero TS0601.js y copiamos el código en el

paramos el docker

en configuration.yaml añadimos el fichero del converter

groups: {}
external_converters:
  - TS0601.js
  - TS0202.js

Arrancamos el docker y ya nos aparece el nuevo dispositivo

Ya podemos ver como empieza a exponer los datos

Físicamente una vez colocado quedaria así , con los grados en Fahrenheit 🙁

  '0xa4c138f9601e97ca':
    friendly_name: '0xa4c138f9601e97ca'
    temperature_calibration: 0
    temperature_precision: 1
    humidity_calibration: 0
    humidity_precision: 0

Crearemos nuestros sensores

  ### TERMOMETRO ARCON CONGELADOR
  
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      unit_of_measurement: "°C"
      device_class: "temperature"
      value_template: "{{ value_json.temperature }}"
      name: "temperatura_lavadero"  
      
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      unit_of_measurement: "°C"
      device_class: "temperature"
      value_template: "{{ value_json.temperature_external }}"
      name: "temperatura_congelador_temperatura"  
  
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      unit_of_measurement: "%"
      device_class: "humidity"
      value_template: "{{ value_json.humidity }}"
      name: "temperatura_congelador_humedad"  
  
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      unit_of_measurement: "%"
      icon: "mdi:battery"
      device_class: "battery"
      value_template: "{{ value_json.battery }}"
    
      expire_after: 86400
      force_update: true
      name: "temperatura_congelador_bateria"  
  
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      icon: "mdi:signal"
      unit_of_measurement: "lqi"
      value_template: "{{ value_json.linkquality }}"    
      name: "temperatura_congelador_estado"  
      
    - state_topic: "zigbee2mqtt/temperatura_congelador"
      availability_topic: "zigbee2mqtt/bridge/state"
      icon: "mdi:calendar-clock"
      value_template: "{{ value_json.last_seen }}"
      name: "temperatura_congelador_ultima_conexion" 

Y después de reiniciar veremos como va guardando los diferentes valores

Y con esto y un bizcocho …………

BONUS : Me tocaba bastante los webs ver los grados en Fahrenheit por lo que mire a ver como ponerlos en Celsius

Para ello cambiaremos el código del converter por este

const tuya = require('zigbee-herdsman-converters/lib/tuya');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const e = exposes.presets;
const ea = exposes.access;

const fzLocal = {
    tuya_weather_station: {
        cluster: 'manuSpecificTuya',
        type: ['commandDataReport', 'commandActiveStatusReport', 'commandMcuSyncTime'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            
            // Time synchro
            if (msg.type === 'commandMcuSyncTime') {
                (async () => {
                    try {
                        const endpoint = msg.endpoint;
                        const now = new Date();
                        
                        const utcTime = Math.round(now.getTime() / 1000);
                        const localTime = utcTime - (now.getTimezoneOffset() * 60);
                        
                        const utcArray = [
                            (utcTime >> 24) & 0xFF,
                            (utcTime >> 16) & 0xFF,
                            (utcTime >> 8) & 0xFF,
                            utcTime & 0xFF,
                        ];
                        
                        const localArray = [
                            (localTime >> 24) & 0xFF,
                            (localTime >> 16) & 0xFF,
                            (localTime >> 8) & 0xFF,
                            localTime & 0xFF,
                        ];
                        
                        const payload = {
                            payloadSize: 8,
                            payload: [...utcArray, ...localArray],
                        };
                        
                        await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {disableDefaultResponse: true});
                        
                        // set 24h time format
                        await new Promise(resolve => setTimeout(resolve, 500));
                        try {
                            await tuya.sendDataPointBool(endpoint, 17, false);
                        } catch (e) {
                            // Ignore if DP 17 don't exist
                        }
                        
                    } catch (error) {
                        // Ignore time synchro errors
                    }
                })();
                
                return {};
            }
            
            if (!msg.data || !msg.data.dpValues) return {};
            
            for (const dpValue of msg.data.dpValues) {
                const dp = dpValue.dp;
                const data = dpValue.data;
                
                let value;
                // temperature
                if (dpValue.datatype === 2) {
                    // Reads the data as an unsigned big-endian 32-bit integer (Negative numbers will be wrong, eg. 429496724.6)
                    // value = data.readUInt32BE(0);
                    // Reads the data as a signed big-endian 32-bit integer (Negative numbers will be correct)
                    value = data.readInt32BE(0);
                } else if (dpValue.datatype === 4) {
                    value = data[0];
                } else {
                    value = data[0];
                }
                
                switch (dp) {
                    // temperature
                    case 1:
                        result.temperature = value / 10;
                        break;
                    // humidity
                    case 2:
                        result.humidity = value;
                        break;
                    // battery_state
                    case 3:
                        result.battery_state = value;
                        result.battery = value === 0 ? 10 : (value === 1 ? 50 : 100);
                        result.battery_low = value === 0;
                        break;
                    // temperature_unit (LCD display)
                    case 9:
                        result.temperature_unit = value === 0 ? 'celsius' : 'fahrenheit';
                        break;
                    // time_format
                    case 17:
                        result.time_format = value ? '12h' : '24h';
                        break;
                    // temperature_external
                    case 38:
                        result.temperature_external = value / 10;
                        break;
                }
            }
            
            return result;
        },
    },
};

const definition = {
    fingerprint: tuya.fingerprint('TS0601', ['_TZE284_hodyryli']),
    model: 'TS0601_weather_station',
    vendor: 'TuYa',
    description: 'Weather station with clock, internal/external temperature and humidity',
    fromZigbee: [fzLocal.tuya_weather_station],
    toZigbee: [tuya.tz.datapoints],
    configure: tuya.configureMagicPacket,
    exposes: [
        e.temperature().withDescription('Internal temperature'),
        e.humidity().withDescription('Internal humidity'),
        e.numeric('temperature_external', ea.STATE)
            .withUnit('°C')
            .withDescription('External temperature sensor'),
        e.battery()
            .withDescription('Battery level (10%=low, 50%=medium, 100%=full)'),
        e.battery_low()
            .withDescription('Battery low warning'),
        e.enum('battery_state', ea.STATE, [0, 1, 2])
            .withDescription('Raw battery state (0=low, 1=medium, 2=full)'),
        e.enum('temperature_unit', ea.STATE_SET, ['celsius', 'fahrenheit'])
            .withDescription('Temperature unit displayed on LCD screen'),
        e.enum('time_format', ea.STATE, ['12h', '24h'])
            .withDescription('Clock time format'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'temperature', tuya.valueConverter.divideBy10],
            [2, 'humidity', tuya.valueConverter.raw],
            [3, 'battery_state', tuya.valueConverter.raw],
            [9, 'temperature_unit', tuya.valueConverter.temperatureUnitEnum],
            [17, 'time_format', tuya.valueConverter.onOff],
            [38, 'temperature_external', tuya.valueConverter.divideBy10],
        ],
    },
};

module.exports = definition;

Por defecto lo tendremos asi

Al consultar los ajustes nos aparece un nuevo selector Celsius / Fahrenheit

Cambiamos a Celsius y pulsamos varias veces para que se actualice

Y tachannnnnnnnnnnnnn ya aparece en Celsius