In order to track the deviation of the 50Hz signal down to 1mHz a deviation of only 0.4us per period needs to be detected. With the noise picked up from the antenna this is impossible. The way to do it is to average the time signal over 1 second, with rising and falling edges tracked that gives us 100 time values to average. In my algorithm I also discard any values that are too far off. With a good and stable power supply and a good input signal quality only 1-3 values get discarded per second. Nevertheless the final signal is more noisy then what could be achieved with taking the signal from an AC supply but it is still pretty accurate.
The signal is picked up using just a MOSFET with some diodes for gate voltage biasing. The output is a distorted sine wave that is then fed into a Schmitt trigger.
The ESP8266 uses an interrupt to track rising and falling edges of the signal, calculates the frequency deviation, puts a millisecond accurate timestamp on the measurement and finally sends it out to a server.
Also it has an RGB led for any user notification and if all runs smoothly it just shows the deviation from blue over green to red, green meaning 50.000Hz.
Time is updated every minute from an NTP server and checked against the time kept from the CPU clock. Any deviation is subtracted and over time, the CPU frequency offset is taken into account when calculating the mains frequency. This should in theory make it immune to (slow) temperature variations or any aging that may affect the CPU frequency. The RTC is optional and only used to synchronize the internal clock when no WiFi connection is available.
Also optional is the use of an SD card to log all the data and, if needed, backup any data that still needs to be sent to the server.
The ESP8266 has the convenience of being an access point as well, so configuration of the device becomes really easy through a simple web page.