Category: Uncategorized

  • My Home Weather Station Build

    Note: This project is currently on hold. I’m restoring these notes from an older site draft and may come back to complete the build later.

    I wanted to design and build my own weather station using a microcontroller.

    Requirements

    1. Run on Arduino
    2. Use COTS hardware components
    3. Require minimal soldering
    4. Be battery operated
    5. Support solar charging
    6. Integrate with OpenHab
    7. Avoid destructive changes to major components

    Hardware

    ItemDetails
    MCUArduino MKR WiFi 1010
    Environmental SensorsMKR ENV Shield
    BatteryLiPo 3.7V 3300mAh
    5V RegulatorAdafruit MiniBoost 5V @ 1A – TPS61023
    Solar ChargerAdafruit Universal USB / DC / Solar Lithium Ion/Polymer Charger (bq24074)
    Solar Panel2W 6V small polysilicon solar panel

    Power

    I knew I wanted the device to live outside and not be permanently plugged in, which meant battery power and a solar panel from the outset.

    Sensors

    Sensors for the MKR WiFi 1010 were easy enough to solve. I opted for an MKR ENV Shield that could simply sit on top.

    The MKR ENV Shield includes three sensors: LPS22HB, HTS221, and TEMT6000.

    LPS22HB

    This is a compact absolute pressure sensor with a range between 260 hPa and 1260 hPa. Atmospheric pressure can be read using the readPressure() function.

    One thing to watch is that the reading needs to be adjusted based on altitude. The sensor is calibrated to provide a reading at sea level, so if your location is above that you will need to apply an offset.

    Find your altitude using GPS or an online source, then use a correction table such as:

    https://novalynx.com/manuals/bp-elevation-correction-tables.pdf

    In my case, I added the offset directly to the reading using a float.

    float pressureAdjustment = 1.64; // kPa
    pressure = ENV.readPressure() + pressureAdjustment;

    As a sanity check, compare your readings with a trusted local weather service. In the UK, the Met Office is the obvious place to start. Local airport weather data can also be useful. In my case, the nearest weather station was roughly 250ft lower than my location, so I had to take that into account when comparing values.

    HTS221

    This sensor provides temperature and humidity readings. The main functions are:

    • readTemperature()
    • readHumidity()

    TEMT6000

    The TEMT6000 is a phototransistor that changes behaviour depending on the amount of light falling on it. It is designed to align reasonably well with human eye sensitivity, so in practice it gives you a good sense of ambient light intensity.

    Its opening angle is ±60°, and while it peaks at 570 nm, it detects light in the range from 440 nm to 800 nm.

    Using the readIlluminance() command returns a value measured in lux.

    When it came to designing an enclosure, I quickly realised that with the solar panel mounted on the top, the phototransistor would be of limited practical value. I still kept the readings, as it was interesting to see whether I could detect dawn, daylight, dusk, and night from within the enclosure.

    Real-Time Clock

    The MKR WiFi 1010 includes a Real-Time Clock (RTC), which I wanted to use partly so that I could track basic uptime behaviour.

    The WiFiNINA library includes a getTime() function that polls the DHCP-advertised NTP server and returns the epoch value. Combined with the setEpoch() function from the RTCZero library, this makes it straightforward to set the internal clock correctly.

    rtc.setEpoch(WiFi.getTime());

    OpenHab

    OpenHab, for all its quirks, is perfectly capable here — but it rewards reading the documentation first rather than charging in and hoping for the best.

    MQTT

    From experience, I knew I wanted each polling cycle to send as little data as possible. I also wanted a stateless, fire-and-forget protocol. MQTT was the obvious fit, and OpenHab already supports it well.

    MQTT works by having clients connect to a broker and publish messages to topics that other clients can subscribe to. In this case, the weather station publishes data and OpenHab subscribes to it.

    As I was already running OpenHab on Ubuntu, I chose Mosquitto as the broker:

    http://www.mosquitto.org

    Recent Mosquitto builds enforce authentication by default. I did not particularly want that complexity on my internal home network, but it is still the sensible default. If you are going down this route, generate credentials for:

    • the IoT device
    • OpenHab
    • a spare admin/user account for yourself

    Documentation for Mosquitto authentication is here:

    https://mosquitto.org/documentation/authentication-methods

    You may also want an MQTT client to inspect exactly what your device is publishing. I used MQTT Explorer:

    https://mqtt-explorer.com

    You will want to think carefully about topic structure up front if you expect to add more IoT devices later.

    Issues

    Debugging

    One of the more annoying practical issues during development was switching cleanly between debugging and normal runtime. Using Serial.print() and Serial.println() everywhere is fine for quick testing, but I wanted an easy way to turn debug output on and off.

    A simple boolean flag worked well enough.

    bool debugMode = false; // set to true for debug
    ...
    if (debugMode) {
      Serial.println("debug message here");
    }

    The same pattern can be used inside functions.

    if (debugMode) {
      Serial.print("Sensor A: ");
      Serial.println(sensorAVal);
    }

    As noted under power management, I also needed a way to toggle low-power mode so that during debugging the Arduino would not go to sleep, while still waiting for the usual interval.

    void powerManagement() {
      switch (SystemState) {
        case RUNNING:
          if (lowPowerMode) {
            WiFi.end();
            SystemState = SLEEPING;
            LowPower.sleep(interval);
          } else {
            SystemState = SLEEPING;
            delay(interval);
          }
          break;
    
        case SLEEPING:
          updateWiFiStatus();
          if (status != WL_CONNECTED) {
            connectWiFi();
          }
          updateWiFiStatus();
          SystemState = RUNNING;
          break;
      }
    }

    Power management

    Power usage when running from battery turned out to be more of an issue than I expected. I was running out of power even after a full day of sun, which suggested I still had more optimisation to do around sleep states and overall power draw.

    This is one of the areas I still intend to revisit if and when I pick the project back up.

  • Obsidian Filter Empty Tasks

    If you use Templates in Obsidian and like to create an empty task item for quick typing, you will often find empty tasks showing up in your task lists.

    The first trick is to exclude your Templates folder from Tasks. You can do this in the Tasks block as below. Replace Templates with wherever you store your templates.

    ```tasks
    path does not include Templates
    ```

    If you also leave empty tasks in your main notes, you can filter them out by including the regex below. This simply matches the start of a string immediately followed by the end of the string, with nothing in between.

    ```tasks
    description regex does not match /^$/
    ```

    If you combine them together as below, you should be covered for most scenarios.

    ```tasks
    description regex does not match /^$/
    path does not include Templates
    ```

    Before

    After

  • IIS + PHP Minor Version Upgrade W/O Web Platform Installer

    I spent far too long trying to work this out.

    On Windows Server with IIS, most people would recommend using the Web Platform Installer (WebPI). The problem is that only certain specific versions are available. If, for example, you want to upgrade from PHP 7.4.13 to 7.4.27, WebPI cannot do it. You have to handle it manually.

    TL;DR: Download the new version, compare the php.ini files, and swap the directories over.

    Instructions

    Download the version of PHP you want directly from PHP for Windows:

    https://windows.php.net/download#php-7.4

    You will usually want the Non-Thread-Safe version.

    Make note of and install any dependencies, such as the Microsoft C++ Redistributable:

    https://aka.ms/vs/16/release/VC_redist.x64.exe

    Locate your current PHP installation directory. In my case, because I had originally installed PHP using WebPI, it was:

    C:\Program Files\PHP

    Extract the downloaded version next to the existing version and rename it with -new, as below.

    You will want Notepad++ with the Compare add-on, or a similar text comparison tool.

    Compare the current php.ini with the new php.ini-production.

    Important: If you originally installed PHP using WebPI, most of the changes will be towards the end of the current php.ini, particularly around extensions. Do not miss these, as I did.

    Copy across all relevant settings from the current configuration to the new php.ini-production, and make note of any newly introduced settings.

    Copy and rename the new php.ini-production to php.ini within the new directory.

    Shut down IIS from IIS Manager — at the server level, not just the site level.

    Swap the PHP directory names around.

    Start IIS again.

    Acknowledgements

    The post below was useful when I was working through this:

    https://www.itgeekrambling.co.uk/wordpress-manual-update-of-php-7-x-on-iis
  • IIS 7 Start / Stop / Restart

    If you need to start, stop, or restart IIS from the command line, the quickest option is to use iisreset.

    Commands

    Start IIS:

    iisreset /start

    Stop IIS:

    iisreset /stop

    Restart IIS:

    iisreset

    Note

    iisreset restarts the entire IIS service, so use it with care on shared or production servers. If you only need to restart a specific site or application pool, IIS Manager or PowerShell may be a better option.

  • SCP a Directory in OSX

    When copying a directory with scp on macOS, the placement of the trailing slash matters.

    If you want to copy the folder source and keep the folder itself in the destination path, use:

    scp -r /path/to/source user@host:/path/for/dest/

    That will copy the source directory into /path/for/dest/.

    For example, if you run:

    scp -r /Users/martyn/source user@example.com:/tmp/

    the result on the remote host will be:

    /tmp/source
  • Rules to follow while naming a SQL Server Instance

    When naming a SQL Server instance, it is worth keeping a few practical rules in mind.

    General rules

    • Instance names are limited to 16 characters.
    • The first character must be a letter.
    • Names cannot contain spaces or special characters such as \, /, :, *, ?, ", <, >, or |.
    • Avoid names that are difficult to distinguish from the host name or from other instances already in use.
    • Keep names short, clear, and meaningful.

    Good practice

    In addition to the technical limits, a sensible naming convention will save confusion later.

    A good instance name should:

    • make it obvious what the instance is for
    • be consistent across environments
    • be easy for administrators and support teams to recognise
    • avoid unnecessary abbreviations unless they are well understood internally

    For example, you might choose names based on:

    • application or service
    • environment, such as DEV, TEST, or PROD
    • region or business unit, if that is relevant

    Examples

    Reasonable examples might include:

    • APP01
    • FINANCE
    • REPORTING
    • CRMTEST

    Poor examples might include:

    • SQL Server
    • 123SQL
    • INSTANCE!
    • THISISFARTOOLONGFORSQL

    Final thought

    The technical rules are simple, but the operational impact of a poor naming convention can linger for years. A clear, consistent standard is usually worth agreeing early.

  • SQL Server Version Numbers

    SQL Server version numbers typically look something like 13.0.5026.0.

    The list below reflects the major version numbering as it stood at the time of writing and is intended as a quick reference rather than a complete current release matrix.

    • SQL Server 2017 — 13.x.xxxx.x
    • SQL Server 2016 — 12.x.xxxx.x
    • SQL Server 2012 — 11.x.xxxx.x
    • SQL Server 2008 R2 — 10.50.xxxx.x (final build 10.50.6000.34)
    • SQL Server 2008 — 10.0.xxxx.xx (final build 10.0.6000.29)
    • SQL Server 2005 — 9.xx.xxxx.xx (final build 9.00.5000.00)

    Determine SQL Server version

    To determine the version of SQL Server, you can use any of the following methods.

    Method 1:
    Connect to the server using Object Explorer in SQL Server Management Studio. Once connected, the version information is typically shown in parentheses, alongside the username used to connect to the instance.

    Method 2:
    Look at the first few lines of the ERRORLOG file for that instance. By default, the error log is located under:

    Program Files\Microsoft SQL Server\MSSQL.n\MSSQL\LOG\ERRORLOG

    and archived logs will appear as ERRORLOG.n.

    The entries may look something like this:

    2011-03-27 22:31:33.50 Server      Microsoft SQL Server 2008 (SP1) -
    10.0.2531.0 (X64)
    
                    March 29 2009 10:11:52
    
                    Copyright (c) 1988-2008 Microsoft Corporation
    
    Express Edition (64-bit)
    on Windows NT 6.1 <X64> (Build 7600: )

    This entry provides the key product information, including version, service pack/update level, architecture, edition, and the operating system version.

    Method 3:
    Connect to the instance and run:

    SELECT @@VERSION

    An example of the output is:

    Microsoft SQL Server 2008 (SP1) -
    10.0.2531.0 (X64)
      March 29 2009 10:11:52 Copyright (c) 1988-2008 Microsoft Corporation
    Express Edition (64-bit)
      on Windows NT 6.1 <X64> (Build 7600: )

    Method 4:
    Connect to the instance and run the following in SQL Server Management Studio:

    SELECT SERVERPROPERTY('productversion'),
           SERVERPROPERTY('productlevel'),
           SERVERPROPERTY('edition')

    This query works for SQL Server 2000 and later.

    It returns:

    • the product version (for example, 10.0.1600.22)
    • the product level (for example, RTM)
    • the edition (for example, Enterprise)

    Reference

    https://support.microsoft.com/en-gb/help/321185/how-to-determine-the-version-edition-and-update-level-of-sql-server-an