• Bringing 120V AC and a 3.3..5V DC thing together - without either smokeless death of the 3.3..5V device or/and jolt-fully death of you - needs some serious separation elements. But it can be done. How depends on the type of fan motor, of course. Assuming, the motor can be controlled by a #triac, you need two optocouplers for the safety of the Espruino board:

    1. one #optocoupler to detect the #zerocrossing of the AC - connected to an input pin watched by a #setWatch
    2. one optocoupler to drive or 'fire' the triac - connected to an output pin controlled by a #digitalPulse.

    Search on the internet for microcontroller controlled ac fan. A straight forward solution approach is shown in this (Arduino) post: http://www.instructables.com/id/Arduino-­controlled-light-dimmer-The-circuit/. Note the cautions at the end of the post!

    Note also that the circuitry shown is built for driving a resistive load - such as an incandescent bulb - where the filament is the resistor. Resistive loads have a decently nice behavior when switched on and off. In electro motors, the inductive loads are coils that build up and change polarity of magnetic fields in defined (times and) spaces. Switching on and off inductive loads need some extra attention and element. The application section of any data sheet about triac and triac driving optocoupler will show you basic circuitry for resistive and inductive loads. For example, see http://pdf.datasheetcatalog.com/datashee­t/motorola/MOC3010.pdf.

    So (little) much to hardware. Now for the software:

    With 60 Hz AC power (as common in US, 50 Hz in Europe), every 8.333[ms] milliseconds (= 1 / 60[Hz] / 2, with 50 Hz every 10[ms]) an AC zero-crossing happens, and you get an interrupt that invokes the function as you pass as callback in setWatch(). Within the next 8.333[ms] you have to switch on the triac with a digitalPulse() that must NOT last beyond the 8.333[ms] period - or in other words - a pulse that has to end decently before the next zero crossing - in order to enable the triac to switch off as well at the zero crossing. The later in the of 8.333[ms] you switch on the triac with the digitalPulse(), the shorter the triac, lesser energy is passed to the motor, and the slower is the motor.

    I have no figures how much of these 8.333[ms] you have to deduct for overhead before your function is called, for the measuring the temperature, calculating the time for the time out for the digitalPulse(). If sure there is plenty time left for the triac to actually be switched on and switched off timely. @Gordon for sure will have some information what the timings are.

    I know for a fact that Espruino has a powerful mechanism to catch interrupts, queue them in order to not loose any during limited time of interrupt rush hours. With each #interrupt, Espruino also captures the time and passes it to the callback function. With that interrupt time it is possible for the software to detect if there is still enough time for the digitalPulse() to switch on the triac. If not, switching on is skip for the current cycle in favor of prepare for a compensated next one.

    This describes so far the software for a complete software controlled switching. To offload ESPRUINO from the actual switching every 8.333[ms] period, an external circuitry can be put in place that handles just the timed switching based on digital or analogue value given by Espruino. A smartly connected #555 #timer circuit can do that. See for example, http://pcbheaven.com/circuitpages/Voltag­e_Controlled_AC_Light_Dimmer/. The zero crossing detection will now be fed to the 555 timer's TRG trigger input pin, and the an Espruino analog output pin will be connected to the CNTR control input pin. Such a delegation of the switching frees up Espruino to just do the sensing and math 'once in a while' - may be every minute - and set the new analogue value.

    A similar approach has been taken in this post at http://www.alfadex.com/dimming-230v-ac-w­ith-arduino-2/. It contains also information about driving resistive and inductive loads.

About

Avatar for allObjects @allObjects started