You can do this using a villager with no trades and a `stat.talkedToVillager` objective. This is because a villager without trades doesn't show the trade interface at all.

Summon an invisible ArmorStand with an invisible, silent Villager as it's passenger, like this:

    /summon ArmorStand <x> <y> <z> {
      Invisible:1b,
      Marker:1b,
      NoGravity:1b,
      Passengers:[{
        id:Villager,
        Silent:1b,
        NoAi:1b,
        Invulnerable:1b,
        CareerLevel:6,
        Offers:{Recipes:[]},
        ActiveEffects:[{
          Id:14b,
          Amplifier:0b,
          ShowParticles:0b,
          Duration:2147483647
        }]
      }]
    }

Copy-paste version of the command:

    /summon ArmorStand <x> <y> <z> {Invisible:1b,Marker:1b,NoGravity:1b,Passengers:[{id:Villager,Silent:1b,NoAi:1b,Invulnerable:1b,CareerLevel:6,Offers:{Recipes:[]},ActiveEffects:[{Id:14b,Amplifier:0b,ShowParticles:0b,Duration:2147483647}]}]}


The armor stand serves purely as a way to hold the villager in place. Play around with `<x> <y> <z>` until you find a good position for the villager. I suggest temporarily removing the villager's invisibility effect for "alignment" by replacing `2147483647` with `0`.

Now, create your objective

    /scoreboard objectives add torchLever stat.talkedToVillager

Use a repeat/chain command block line to run the following commands:

    /execute @a[x=X,y=Y,z=Z,r=R,score_torchLever_min=1] ~ ~ ~ <your command>
    /scoreboard players set @a torchLever 0

Replace `X`, `Y`, `Z` and `R` with appropriate values. This is to prevent triggering your torch lever when interacting with *any* villagers.