replacing FX-101 board in a Haier HVTEC12DABS

The Haier HVTEC12DABS is a 12-bottle wine fridge with a 2-zone thermoelectric (peltier) cooling setup.

My fridge started acting up. Beeping on start, front panel dead, no cooling. From what I read in a very useful thread at All About Circuits it’s possible to replace commonly blown capacitors, fuses, and transistors. But I am not that handy and I’d probably mess something else up in the process.

So I looked for replacement boards. This unit has two FX-101B boards, manufactured by “Foshan Hanyi Computer”:

The board is labelled as “FX-101B 10.5V PCB120606F1”. There is another marking “SH14611” with a date of “12.07.12”.

I wanted to replace both boards but the FX-101B is impossible to find. The “B” variant must have been made specifically for Haier, as other wine fridges have an FX-101 or FX-102 board. The differences I found:

  • the TEC (thermo-electric cooler) plug is a spade terminal rather than pins
  • there is an additional NTC (thermristor) connector for temperature control

I found that they sell these boards on Aliexpress in all different varieties (search for “FX-101 board”). But I could not find an FX-101B board, only the FX-101 and FX-102 which is apparently compatible. So I took a shot – $72.10 shipped for two FX-101 boards, from China. Now I’m thinking the FX-102 might have been a new board with better components but I didn’t really know much at the time and just went with the part I thought was the most compatible.

Note: Stock image because I forgot to take a picture before I put them in. When they arrived, they were marked 110v and 10.5v as requested. I found out later that if you find a 110v 12.5v board, that should work as well. 220v will obviously not work if your previous board is 110v and vice versa. Notice the different connector for the TEC power and the new NTC connector in the upper right.

First I had to cut off the existing TEC connector in the fridge and crimp spade disconnects to them which was a $4 purchase from Home Depot. Note: the FAN1 and FAN2 are different! One is hot side and one is cool side. The cool side (inside) should always spin, the hot side (outside) will only spin if the board is cooling. Switch your fan connectors if this happens. I plugged everything back in and started the wine cooler up.

Joy! The front panel was no longer blinking and chirping and it looked like it was cooling. But alas, the red lights on the back of the boards were lit up. This means that the unit has power but has not been requested to cool. The cool side (inside) fans were spinning. The hot side (outside) fans were not spinning. Multimeter showed no power to the TEC. I figured this had something to do with the new NTC connector and that maybe the board was expecting to be turned on via a thermristor instead of the control from the front panel.

I used a jumper to short the NTC pins together and the cooler came alive. The green LED lit up and the back fans started spinning. It then cooled down the set temperature.

I confirmed against my suspicions, even with the NTC pins jumped, the front panel temperature was still controlling cooling activation. I had thought that this would have made the fridge cool infinitely as it thought it was too warm (a thermristor will increase resistance as it gets hotter). Why this is, I don’t know. I guess the remote control overrides the thermristor, or, if it detects very low resistance it assumes there is no thermristor. Now the fridge cools to the requested temperature and turns off when not needed. Working like brand new!

Attaching Rules conditions to a config entity

Enhancing modules with Rules-based conditions was very easy in D7. Using hook_default_rules_configuration we could dynamically generate a bunch of rules called mymodule_rule_[some_key], use rules_ui()->config_menu() to add the menu items for the Rules admin UI, then invoke the generated components to evaluate conditions. Every entity or option would have its own Rules component that we can edit and add arbitrary conditions. Some examples of this in D7 were:

  • Payment methods (Ubercart/Commerce)
  • Coupons
  • Tax rules
  • Block visibility
  • User access or eligibility

And anything where you could not possibly know of the conditions that would be needed. Some of the above were changed to use Core conditions in D8, but that didn’t cut it for our use case since I could not possibly write a new condition for every requirement that came up. Real life examples of these are:

  • A user can only claim a certain kind of course credit when the credit code on the course contains specific characters and the user is from Florida.
  • The user can only use the payment method when there is a valid role attached to the user and specific products are in the cart.
  • A user is not eligible to receive a certain type of credit when they are eligible to receive a certain type of credit.
  • A quiz taker can only see correct answers once two weeks have passed and the user exhausted two attempts.

These aren’t out of the ordinary and we would be writing custom PHP if/else trees every day. For a SaaS-like product this is not ideal.

It’s a little trickier to add arbitrary conditions to entities but well worth it in the end. Rules provides a test module that you can look at: rules_test_ui_embed. This example illustrates using 1 rule component embedded into a page. But we need to build Rules into all instances of a configuration entity.

Rules provides an interface RulesUiComponentProviderInterface that we can use to store component configuration on our entity types. This was added in and but so far, there don’t seem to be any contributed modules that implement this! Rules does use it for its own action and condition components.

There is documentation for extending Rules with new conditions and actions, but it is pretty lacking around integration. There is some embedded developer documentation so let’s take a look.

If we look at rules_test_ui_embed we see that there is some sort of plugin file – rules_test_ui_embed.rules_ui.yml. That must define something!


The above defines a Rules UI plugin which will create routes on rules_test_ui_embed.settings .The configuration for the Rules component will be saved to rules_test_ui_embed.settings under the conditions key. But that doesn’t work for us, we need to have multiple components on multiple entities.

There’s another parameter in RulesUiConfigHandler we can use to allow wildcard editing of components: config_parameter

It appears that config_parameter and config_key can be used to dynamically set which configuration object and key will be updated. With a little trial and error I applied it to Quiz feedback types. Feedback types hold sets of review options that display feedback to quiz takers after they answer a question or finish an entire quiz. They can also be used for post-review feedback, in the case of revisiting the quiz after 2 weeks. Only seeing correct answers after 3 attempts, only seeing instructor feedback once given a role, etc…

Let’s assume that we already have a QuizFeedbackType entity to allow creation of custom feedback “times”, and all the edit forms are already set up. We want to add conditions to each feedback type so that we can conditionally display their items. In Quiz we have two built in: “Question” and “End”.

Define route and *.rules_ui.yml

This will indicate that we want Rules UI functionality appended to a route that we will also create. It will also tell Rules that we want the component to be saved onto the object loaded from the quiz_feedback_type parameter. Note how _rules_ui option on the route matches the plugin name defined in quiz_rules.ui.yml:



Define new form for editing a component

This is a normal form that extends ConfigFormBase, but is provided with a Rules UI handler from the plugin definition that matches the route above. Most of this code is copied from rules_test_ui_embed:


In buildForm we take in the Rules UI handler and use it to generate the condition form. In submitForm, the Rules UI handler will notify our Rules component “provider” that there is a component that has to be saved.

Implement RulesUiComponentProviderInterface

The rulesUiHandler from above requires the entity type to handle getting the Rules component and saving it onto itself since we are not specifying a static config_name or config_key We add the component property to config_export, then we implement RulesUiComponentProviderInterface and implement the 2 methods:

  • In getComponent() we check to see if the entity already has conditions, and return a RulesComponent. If it does not, we provide a default that intakes a QuizResult entity to evaluate.
  • In updateFromComponent(), we get the RulesComponent and store it on the entity.

And there it goes, components being attached to entities.

Now that the components are stored on an entity that implements RulesUiComponentProviderInterface, we can invoke the rule in our code to validate the conditions:

replacing the haproxy error page in openshift origin

first, create a configmap secret which will contain the 503 page

then create it

now you need to add it as a volume

and patch the router config (see for why this is necessary)

selinux also has to be disabled on the router box (for now)

stop behat on 500 errors with mink

I had some issues diagnosing 500 errors that were happening with Mink. The main issue being that a page would 500, but then the test would proceed and fail a later step. Unfortunately the HTML/screenshot that was captured does not capture the error, but instead captures the assertion which doesn’t help debug.

It’s possible to react after a step and check if the last Mink request was a 500 or not. This way, we fail on the 500, and not on the subsequent assertions.


PHP commandline OAuth authorization for JIRA

I needed to get a user’s OAuth credentials from the commandline, for some commandline tools to work (Drush).

You will need OAuth installed from PECL for this, and have an OAuth link set up in JIRA (or whatever OAuth provider you are using).


launch a jenkins slave via drush

If you already have Drush aliases set up for your live machines, deploy those aliases to your CI server, and use them to launch your nodes (instead of copying the SSH info).

Create a new “Dumb slave” but instead of “SSH slave”, select “Launch slave via execution”

This is the command to use:

Jenkins will run the command which sets up the remoting capabiliity.